如何使用C ++ Builder为XML节点分配名称空间和前缀

时间:2016-07-09 00:25:33

标签: xml dom c++builder irs

我使用XML数据绑定向导为IRS XML规范文件创建一个类。我有两个问题无法找到答案(而且我花了好几个小时的努力)。

这是我需要的XML输出片段:

<?xml version="1.0" encoding="UTF-8"?>
<h1:ACAUIBusinessHeader xmlns="urn:us:gov:treasury:irs:ext:aca:air:7.0" xmlns:irs="urn:us:gov:treasury:irs:common" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:acabushdr="urn:us:gov:treasury:irs:msg:acabusinessheader" xmlns:h1="urn:us:gov:treasury:irs:msg:acauibusinessheader" xsi:schemaLocation="urn:us:gov:treasury:irs:msg:acauibusinessheader IRS-ACAUserInterfaceHeaderMessage.xsd">
    <acabushdr:ACABusinessHeader>
        <UniqueTransmissionId>00000000-0000-0000-0000-000000000000:SYS12:BB000::T</UniqueTransmissionId>
        <irs:Timestamp>2001-12-17T09:30:47Z</irs:Timestamp>
    </acabushdr:ACABusinessHeader>
    <ACATransmitterManifestReqDtl>
        <PaymentYr>1000</PaymentYr>
        <PriorYearDataInd>1</PriorYearDataInd>
        <irs:EIN>000000000</irs:EIN>
    </ACATransmitterManifestReqDtl>
</h1:ACATransmitterManifestReqDtl>

如您所见,根节点不使用默认的xmlns命名空间。如果我添加&#34; h1:&#34; GetDocBinding()调用中的名称的前缀然后它添加&#34; h1:&#34;所有子节点的前缀不是我需要的。

我还手动编辑了数据绑定向导创建的类,以便我可以使用DeclareNamespace()方法定义额外的命名空间。然而,当我尝试使用RegisterChildNode()方法的可选第三个参数来定义URI时,当我尝试为该节点使用该属性时,它会崩溃。

以下是已编辑课程的代码段:

    _di_IXMLTransmitterACAUIBusinessHeaderType __fastcall GetACAUIBusinessHeader(Xml::Xmlintf::_di_IXMLDocument Doc)
    {
        return (_di_IXMLTransmitterACAUIBusinessHeaderType) Doc->GetDocBinding("ACAUIBusinessHeader", __classid(TXMLTransmitterACAUIBusinessHeaderType), eACA_UI_Header_TargetNamespace);
    };

    _di_IXMLTransmitterACAUIBusinessHeaderType __fastcall GetACAUIBusinessHeader(Xml::Xmldoc::TXMLDocument *Doc)
    {
        Xml::Xmlintf::_di_IXMLDocument DocIntf;
        Doc->GetInterface(DocIntf);
        return GetACAUIBusinessHeader(DocIntf);
    };

    _di_IXMLTransmitterACAUIBusinessHeaderType __fastcall LoadACAUIBusinessHeader(const System::UnicodeString& FileName)
    {
        return (_di_IXMLTransmitterACAUIBusinessHeaderType) Xml::Xmldoc::LoadXMLDocument(FileName)->GetDocBinding("ACAUIBusinessHeader", __classid(TXMLTransmitterACAUIBusinessHeaderType), eACA_UI_Header_TargetNamespace);
    };

    _di_IXMLTransmitterACAUIBusinessHeaderType __fastcall  NewACAUIBusinessHeader()
    {
        return (_di_IXMLTransmitterACAUIBusinessHeaderType) Xml::Xmldoc::NewXMLDocument()->GetDocBinding("ACAUIBusinessHeader", __classid(TXMLTransmitterACAUIBusinessHeaderType), eACA_UI_Header_TargetNamespace);
    };

    // TXMLTransmitterACAUIBusinessHeaderType

    void __fastcall TXMLTransmitterACAUIBusinessHeaderType::AfterConstruction(void)
    {
        RegisterChildNode(System::UnicodeString("ACABusinessHeader"), __classid(TXMLACABulkBusinessHeaderRequestType_air7_0), "urn:us:gov:treasury:irs:common");
        RegisterChildNode(System::UnicodeString("ACATransmitterManifestReqDtl"), __classid(TXMLACATrnsmtManifestReqDtlType_air7_0));
        Xml::Xmldoc::TXMLNode::AfterConstruction();
    };

    UnicodeString __fastcall TXMLTransmitterACAUIBusinessHeaderType::Get_irs_NS()
    {
        return TXMLNode::AttributeNodes->Nodes[UnicodeString("xmlns:irs")]->Text;
    };

    void __fastcall TXMLTransmitterACAUIBusinessHeaderType::Set_irs_NS(UnicodeString Value)
    {
        //TXMLNode::SetAttributeNS(UnicodeString("xmlns:irs"), "", Value);
        TXMLNode::DeclareNamespace(UnicodeString("irs"), Value);
    };
// More of the same

这是我编写的一些初步代码,用于使用类测试输出:

Manifest = new TXMLDocument(GetWindow());
        Manifest->DOMVendor = GetDOMVendor("MSXML"); // NOT cross platform compatible
        Manifest->NodeIndentStr = char(9); // TAB character
        Manifest->Options = Manifest->Options << doNodeAutoIndent << doAttrNull << doAutoPrefix;

        Manifest_root = GetACAUIBusinessHeader(Manifest);

        Manifest->Version = "1.0";
        Manifest->Encoding = "UTF-8";

        // Assign NameSpaces and Schema
        Manifest_root->irs_NS = "urn:us:gov:treasury:irs:common";
        Manifest_root->xsi_NS = "http://www.w3.org/2001/XMLSchema-instance";
        Manifest_root->acabushdr_NS = "urn:us:gov:treasury:irs:msg:acabusinessheader";
        Manifest_root->h1_NS = "urn:us:gov:treasury:irs:msg:acauibusinessheader";
        Manifest_root->schemaLocation = "urn:us:gov:treasury:irs:msg:acauibusinessheader IRS-ACAUserInterfaceHeaderMessage.xsd";

        Manifest_root->ACABusinessHeader->UniqueTransmissionId = "token"; // Just for testing
        Manifest_root->ACABusinessHeader->Timestamp = "2001-12-17T09:30:47Z"; // Just for testing

        Manifest_root->ACATransmitterManifestReqDtl->PaymentYr = "2016";
        Manifest_root->ACATransmitterManifestReqDtl->PriorYearDataInd = "1";
        Manifest_root->ACATransmitterManifestReqDtl->EIN = "000000000";

如果我在上面的代码中取出RegisterChildNode()方法的第三个参数,它不会崩溃,但输出不正确:

<?xml version="1.0" encoding="UTF-8"?>
<ACAUIBusinessHeader xmlns="urn:us:gov:treasury:irs:ext:aca:air:7.0" xmlns:irs="urn:us:gov:treasury:irs:common" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:acabushdr="urn:us:gov:treasury:irs:msg:acabusinessheader" xmlns:h1="urn:us:gov:treasury:irs:msg:acauibusinessheader" xsi:schemaLocation="urn:us:gov:treasury:irs:msg:acauibusinessheader IRS-ACAUserInterfaceHeaderMessage.xsd">
    <ACABusinessHeader>
        <UniqueTransmissionId>token</UniqueTransmissionId>
        <Timestamp>2001-12-17T09:30:47Z</Timestamp>
    </ACABusinessHeader>
    <ACATransmitterManifestReqDtl>
        <PaymentYr>2016</PaymentYr>
        <PriorYearDataInd>1</PriorYearDataInd>
        <EIN>000000000</EIN>
    </ACATransmitterManifestReqDtl>
</ACAUIBusinessHeader>

正如您所看到的,根节点ACAUIBusinessHeader,ACABusinessHeader节点以及Timestamp&amp;节点所需的前缀(名称空间)。缺少EIN节点,我不知道如何正确地调整类以分配它们。

1 个答案:

答案 0 :(得分:1)

I was finally able to figure out how to adapt the generated XML classes to get the desired output. I moved the DeclareNamespace() calls to the AfterConstruction() function, and had to change the Get() function calls (and Set() when applicable) for those nodes that used different namespaces.

Here's the first part of the adapted code:

_di_IXMLTransmitterACAUIBusinessHeaderType __fastcall GetACAUIBusinessHeader(Xml::Xmlintf::_di_IXMLDocument Doc)
{
    return (_di_IXMLTransmitterACAUIBusinessHeaderType) Doc->GetDocBinding("n1:ACAUIBusinessHeader", __classid(TXMLTransmitterACAUIBusinessHeaderType), nsN1);
};

_di_IXMLTransmitterACAUIBusinessHeaderType __fastcall GetACAUIBusinessHeader(Xml::Xmldoc::TXMLDocument *Doc)
{
    Xml::Xmlintf::_di_IXMLDocument DocIntf;
    Doc->GetInterface(DocIntf);
    return GetACAUIBusinessHeader(DocIntf);
};

_di_IXMLTransmitterACAUIBusinessHeaderType __fastcall LoadACAUIBusinessHeader(const System::UnicodeString& FileName)
{
    return (_di_IXMLTransmitterACAUIBusinessHeaderType) Xml::Xmldoc::LoadXMLDocument(FileName)->GetDocBinding("n1:ACAUIBusinessHeader", __classid(TXMLTransmitterACAUIBusinessHeaderType), nsN1);
};

_di_IXMLTransmitterACAUIBusinessHeaderType __fastcall  NewACAUIBusinessHeader()
{
    return (_di_IXMLTransmitterACAUIBusinessHeaderType) Xml::Xmldoc::NewXMLDocument()->GetDocBinding("n1:ACAUIBusinessHeader", __classid(TXMLTransmitterACAUIBusinessHeaderType), nsN1);
};

// TXMLTransmitterACAUIBusinessHeaderType

void __fastcall TXMLTransmitterACAUIBusinessHeaderType::AfterConstruction(void)
{
    TXMLNode::DeclareNamespace(System::UnicodeString(""), nsACA); // default xmlns
    TXMLNode::DeclareNamespace(System::UnicodeString("irs"), nsIRS);
    TXMLNode::DeclareNamespace(System::UnicodeString("xsi"), nsXSI);
    TXMLNode::DeclareNamespace(System::UnicodeString("acabushdr"), nsACAbushdr);
    TXMLNode::DeclareNamespace(System::UnicodeString("n1"), nsN1);
    RegisterChildNode(System::UnicodeString("ACABusinessHeader"), __classid(TXMLACABulkBusinessHeaderRequestType_air7_0), nsACAbushdr);
    RegisterChildNode(System::UnicodeString("ACATransmitterManifestReqDtl"), __classid(TXMLACATrnsmtManifestReqDtlType_air7_0), nsACA);
    TXMLNode::SetAttribute(System::UnicodeString("xsi:schemaLocation"), SchemaLoc);
    Xml::Xmldoc::TXMLNode::AfterConstruction();
};

_di_IXMLACABulkBusinessHeaderRequestType_air7_0 __fastcall TXMLTransmitterACAUIBusinessHeaderType::Get_ACABusinessHeader()
{
    _di_IXMLACABulkBusinessHeaderRequestType_air7_0 result = GetChildNodes()->FindNode("acabushdr:ACABusinessHeader", nsACAbushdr);
    if(result == NULL)
        result = GetChildNodes()->Nodes[System::UnicodeString("acabushdr:ACABusinessHeader")]; // creates it
    return result;
};

_di_IXMLACATrnsmtManifestReqDtlType_air7_0 __fastcall TXMLTransmitterACAUIBusinessHeaderType::Get_ACATransmitterManifestReqDtl()
{
    _di_IXMLACATrnsmtManifestReqDtlType_air7_0 result = GetChildNodes()->FindNode("ACATransmitterManifestReqDtl", nsACA);
    if(result == NULL) // Because this XML document doesn't use the default xmlns for the "root" node, but this node DOES use the default xmlns, it has to be added this way to match up the namespace
        result = AddChild("ACATransmitterManifestReqDtl", nsACA); // creates it
    return result;
};

The "nsACA" and its cousins are just constant UnicodeStrings. As you can see I also had to add the "n1:" prefix/namespace to the name of the root node in the GetDocBinding() calls. The namespace is later declared in the AfterConstruction() function. For the nodes who use the "irs:" prefix/namespace it was enough to simply add it to the node string name after it was declared in the AfterConstruction() function. Here's an example:

System::UnicodeString __fastcall TXMLACABulkBusinessHeaderRequestType_air7_0::Get_Timestamp()
{
    return GetChildNodes()->Nodes[System::UnicodeString("irs:Timestamp")]->NodeValue.operator System::UnicodeString();
};

void __fastcall TXMLACABulkBusinessHeaderRequestType_air7_0::Set_Timestamp(System::UnicodeString Value)
{
    GetChildNodes()->Nodes[System::UnicodeString("irs:Timestamp")]->NodeValue = Value;
};

There's a little more involved when one of the child nodes doesn't inherit it's namespace from the parent node and is using the default xmlns namespace (which doesn't have a prefix like the "irs:" example). Here's how I handled that case for the UniqueTransmissionId node:

System::UnicodeString __fastcall TXMLACABulkBusinessHeaderRequestType_air7_0::Get_UniqueTransmissionId()
{
    _di_IXMLNode result = GetChildNodes()->FindNode("UniqueTransmissionId", nsACA);
    if(result == NULL)
        return EmptyStr;
    return result->NodeValue.operator System::UnicodeString();
    //return GetChildNodes()->Nodes[System::UnicodeString("UniqueTransmissionId")]->NodeValue.operator System::UnicodeString();
};

void __fastcall TXMLACABulkBusinessHeaderRequestType_air7_0::Set_UniqueTransmissionId(System::UnicodeString Value)
{
    _di_IXMLNode result = GetChildNodes()->FindNode("UniqueTransmissionId", nsACA);
    if(result == NULL) // Because this XML document doesn't use the default xmlns for the "root" node, but this node DOES use the default xmlns, it has to be added this way to match up the namespace
        result = AddChild("UniqueTransmissionId", nsACA); // creates it
    result->NodeValue = Value;
    //GetChildNodes()->Nodes[System::UnicodeString("UniqueTransmissionId")]->NodeValue = Value;
};

And here is the final output:

<?xml version="1.0" encoding="UTF-8"?>
<n1:ACAUIBusinessHeader xmlns="urn:us:gov:treasury:irs:ext:aca:air:7.0" xmlns:irs="urn:us:gov:treasury:irs:common" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:acabushdr="urn:us:gov:treasury:irs:msg:acabusinessheader" xmlns:n1="urn:us:gov:treasury:irs:msg:acauibusinessheader" xsi:schemaLocation="urn:us:gov:treasury:irs:msg:acauibusinessheader IRS-ACAUserInterfaceHeaderMessage.xsd">
    <acabushdr:ACABusinessHeader>
        <UniqueTransmissionId>token</UniqueTransmissionId>
        <irs:Timestamp>2001-12-17T09:30:47Z</irs:Timestamp>
    </acabushdr:ACABusinessHeader>
    <ACATransmitterManifestReqDtl>
        <PaymentYr>2016</PaymentYr>
        <PriorYearDataInd>1</PriorYearDataInd>
        <irs:EIN>000000000</irs:EIN>
    </ACATransmitterManifestReqDtl>
</n1:ACAUIBusinessHeader>

Hopefully this will prove helpful to anyone working with the Delphi/C++ Builder XML Data Binding Wizard. It appears that it can only handle a single namespace on its own, but with these sorts of changes it can still be a good place to start from.