开发者

Append Multiple Similar XML Nodes to XML Document

开发者 https://www.devze.com 2023-02-17 10:25 出处:网络
I\'m currently working with an XML request, and am trying to create a Reply Document that has multiple child nodes of the same name in the call, so what I\'m trying to return is:

I'm currently working with an XML request, and am trying to create a Reply Document that has multiple child nodes of the same name in the call, so what I'm trying to return is:

&开发者_StackOverflowlt;Reply Document>
    <ConfirmationItem name = "One">
         <ItemDetail />
    </ConfirmationItem>
    <ConfirmationItem name = "Two">
         <ItemDetail />
    </ConfirmationItem>
    ...
    <ConfirmationItem name = "Twenty">
         <ItemDetail />
    </ConfirmationItem>
</Reply Document> 

I did a bit of research and found this thread: XmlReader AppendChild is not appending same child value in which the accepted answer was that the OP had to create new Elements to be able to append to the end instead of overwrite the first.

My original code is below, it creates the XmlNode from the incoming Request and appends the result to the XmlDocument itself:

//p_transdoc is the XmlDocument that holds all the items to process.  
XmlNodeList nodelst_cnfrm = p_transdoc.SelectNodes("//OrderRequest");
foreach (XmlNode node in nodelst_cnfrm)
{
     //this is just an XML Object 
     XmlNode node_cnfrm_itm = this.CreateElement("ConfirmationItem");
     node_cnfrm_itm.Attributes.Append(this.CreateAttribute("name")).InnerText = p_transdoc.Attributes["name"].InnerText;

     XmlNode node_itmdtl = this.CreateElement("ItemDetail");
     node_cnfrm_itm.AppendChild(node_itmdtl);
//xml_doc is the return XML request                    
xml_doc.AppendChild(node_cnfrm_itm);
}

So after reading that thread and the answer, I tried to change the code to use a new XmlElement each pass through.

//p_transdoc is the XmlDocument that holds all the items to process.  
XmlNodeList nodelst_cnfrm = p_transdoc.SelectNodes("//OrderRequest");
foreach (XmlNode node in nodelst_cnfrm)
{
     XmlElement node_cnfrm_itm = new XmlElement();
     node_cnfrm_itm = this.CreateElement("ConfirmationItem");
     node_cnfrm_itm.Attributes.Append(this.CreateAttribute("name")).InnerText = p_transdoc.Attributes["name"].InnerText;

     XmlElement node_itmdtl = new XmlElement();
     node_itmdtl = this.CreateElement("ItemDetail");
     node_cnfrm_itm.AppendChild(node_itmdtl);
     //xml_doc is the return XML request                    
     xml_doc.AppendChild(node_cnfrm_itm);
}   

But not only does that not work, it returns a server error. So I've come to you for help. Right now this code is just returning one ConfirmationItem. How would I be able to append the ConfirmationItem to the end of the Document instead of overwrite it, to be able to return as many as were sent in?

(I should point out that this code has been heavily formatted for ease of readability, simplicity, and to reduce clutter. Any typographical errors are purely because of the Asker's internal failure at effective proofreading).


Assuming xml_doc is the xml with the ConfirmationItems you need to create the XmlElements with the new XmlDocument. XmlDocument.CreateElement. Hence I use the Linq extension method OfType<>() here to only return the XmlNode objects of the type XmlElement.

// dummy data
XmlDocument p_transdoc = new XmlDocument();
p_transdoc.LoadXml(@"
<root name='rootAttribute'>
    <OrderRequest name='one' />
    <OrderRequest name='two' />
    <OrderRequest name='three' />
</root>
");

XmlDocument xml_doc = new XmlDocument();
xml_doc.LoadXml("<ReplyDocument />");

foreach (var node in p_transdoc.SelectNodes("//OrderRequest").OfType<XmlElement>())
{
    XmlElement node_cnfrm_itm = xml_doc.CreateElement("ConfirmationItem");
    node_cnfrm_itm = xml_doc.DocumentElement.AppendChild(node_cnfrm_itm) as XmlElement;
    node_cnfrm_itm.SetAttribute("name", node.GetAttribute("name"));

    XmlElement node_itmdtl = xml_doc.CreateElement("ItemDetail");
    node_itmdtl = node_cnfrm_itm.AppendChild(node_itmdtl) as XmlElement;
}

The method CreateElement returns an XmlElement so you can use the methods SetAttribute and GetAttribute.

The code: p_transdoc.Attributes["name"].InnerText doesn't seem right. If you want to get the attributes for the root element of the document you need to type: p_transdoc.DocumentElement.GetAttribute("name")

IMO this is MUCH easier if you're using Linq to XML.

In Linq to XML this would be similar to (some variables have different names):

 // dummy data
var transDoc = XDocument.Parse(@"
<root name='rootAttribute'>
    <OrderRequest name='one' />
    <OrderRequest name='two' />
    <OrderRequest name='three' />
</root>");

var xmlDoc = XDocument.Parse("<ReplyDocument />");

xmlDoc.Root.Add(
    transDoc.Root.Elements("OrderRequest").Select(o => 
        new XElement("ConfirmationElement",
            new XAttribute("name", (string)o.Attribute("name")),
            new XElement("ItemDetail"))));

Both examples output:

<ReplyDocument>
  <ConfirmationElement name="one">
    <ItemDetail />
  </ConfirmationElement>
  <ConfirmationElement name="two">
    <ItemDetail />
  </ConfirmationElement>
  <ConfirmationElement name="three">
    <ItemDetail />
  </ConfirmationElement>
</ReplyDocument> 
0

精彩评论

暂无评论...
验证码 换一张
取 消