将多个相似的 XML 节点附加到 XML 文档

Posted

技术标签:

【中文标题】将多个相似的 XML 节点附加到 XML 文档【英文标题】:Append Multiple Similar XML Nodes to XML Document 【发布时间】:2011-03-15 14:12:02 【问题描述】:

我目前正在处理一个 XML 请求,并且正在尝试创建一个回复文档,该文档在调用中具有多个同名子节点,所以我想要返回的是:

<Reply Document>
    <ConfirmationItem name = "One">
         <ItemDetail />
    </ConfirmationItem>
    <ConfirmationItem name = "Two">
         <ItemDetail />
    </ConfirmationItem>
    ...
    <ConfirmationItem name = "Twenty">
         <ItemDetail />
    </ConfirmationItem>
</Reply Document> 

我做了一些研究,发现了这个线程:XmlReader AppendChild is not appending same child value,其中接受的答案是 OP 必须创建新元素才能附加到末尾而不是覆盖第一个。

我的原始代码如下,它从传入的请求创建 XmlNode 并将结果附加到 XmlDocument 本身:

//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);

因此,在阅读了该线程和答案后,我尝试更改代码以使用新的 XmlElement 每次通过。

//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);
   

但这不仅不起作用,还会返回服务器错误。所以我来找你帮忙了。现在这段代码只返回一个 ConfirmationItem。我如何能够将 ConfirmationItem 附加到 Document 的末尾而不是覆盖它,以便能够返回与发送的一样多的内容?

(我应该指出,为了便于阅读、简化和减少混乱,这段代码已经过大量格式化。任何印刷错误纯粹是因为提问者在有效校对方面的内部失败)。

【问题讨论】:

'this'是什么样的对象? 【参考方案1】:

假设 xml_doc 是带有 ConfirmationItems 的 xml,您需要使用新的 XmlDocument 创建 XmlElements。 XmlDocument.CreateElement。因此我在这里使用Linq 扩展方法OfType&lt;&gt;() 只返回XmlElement 类型的XmlNode 对象。

// 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;

CreateElement 方法返回一个 XmlElement,因此您可以使用SetAttributeGetAttribute 方法。

代码:p_transdoc.Attributes["name"].InnerText 似乎不对。如果要获取文档根元素的属性,需要输入:p_transdoc.DocumentElement.GetAttribute("name")

如果您使用 Linq to XML,IMO 会容易得多。

在 Linq to XML 中,这类似于(某些变量具有不同的名称):

 // 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"))));

两个示例输出:

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

【讨论】:

感谢您非常明确的回复。我将不得不对 Linq to XML 进行更多研究,以完全理解第二个示例。第一个例子虽然我有疑问,也许这是因为我没有经验。但是,我没有看到您将元素本身附加到何处。这是系统自动执行的操作吗? 另外,只是想指出:p_transdoc.Attributes["name"].InnerText 绝对不是最优雅的解决方案(我现在知道了!:)),但它是可行的,在至少在 foreach 循环本身的上下文中。它从 OrderRequest 节点本身获取 name 属性,因为这是从 p_transdoc.SelectNodes("//OrderRequest");只是想为您提供信息:) 我创建了节点并将其附加到文档的一行中:xml_doc.DocumentElement.AppendChild(xml_doc.CreateElement("ConfirmationItem"));。为了提高可读性,您可以更改为: var n = xml_doc.CreateElement("ConfirmationItem"); n = xml_doc.DocumentElement.AppendChild(n); @Gobbledigook 我更改了第一个代码示例并分隔了创建元素并将元素附加到文档的行。

以上是关于将多个相似的 XML 节点附加到 XML 文档的主要内容,如果未能解决你的问题,请参考以下文章

将特定的 XML 节点拉入 HTML 文档

Xpath语法

使用C#XML文档类修改子节点值

XML字符串到XML文档

如何通过将树视图中的节点绑定到 XML 文档的节点来显示树节点

将字符串 XML 片段转换为 Java 中的文档节点