【问题标题】:Convert contents of an XmlNodeList to a new XmlDocument without looping将 XmlNodeList 的内容转换为新的 XmlDocument 而不循环
【发布时间】:2015-06-22 08:47:31
【问题描述】:

我有使用 XPath 过滤的 Xml(类似于此的查询):

    XmlNodeList allItems = 
xDoc.SelectNodes("//Person[not(PersonID = following::Person/PersonID)]");

这会过滤我原始 Persons Xml 中的所有重复项。我想从上面生成的 XmlNodeList 创建一个新的 XmlDocument 实例。目前,我能看到的唯一方法是遍历 XmlNode 的列表并构建一个 Xml 字符串(这样):

        XmlNodeList allItems = xDoc.SelectNodes("//Person[not(PersonID = following::Person/PersonID)]");
        StringBuilder xml = new StringBuilder("<Persons>");

        foreach (XmlNode node in allItems)
            xml.Append(node.OuterXml);

        xml.Append("</Persons>");

        XmlDocument newXDoc = new XmlDocument();
        newXDoc.LoadXml(xml.ToString());

必须有更有效的方法来做到这一点?

【问题讨论】:

  • 出于兴趣,你必须使用XPath吗?你必须使用XmlDocument吗? LINQ to XML 使这类事情(实际上几乎所有事情......)变得更简单。
  • 我并不珍视它被加载到 XmlDocument 中。实际上,我使用它的输出来填充 DataTable。所以我真正感兴趣的是字符串 XML。我确实将 foreach 转换为 Linq,但它的执行速度似乎和上面的 foreach 一样慢:-|

标签: c# xml xpath xmldocument xmlnodelist


【解决方案1】:

如果您乐意将其转换为 LINQ to XML,那真的很简单:

XDocument original = ...; // However you load the original document
// Separated out for clarity - could be inlined, of course
string xpath = "//Person[not(PersonID = following::Person/PersonID)]"

XDocument people = new XDocument(
    new XElement("Persons",
        original.XPathSelectElements(xpath)
    )
);

您绝对不需要将每个节点转换为字符串并返回。您也不需要使用XmlDocument,但它不会像使用 LINQ to XML 那样简单:)

【讨论】:

  • 使用这种方法出现错误 Jon “非空白字符不能添加到内容中。”。我使用的代码如下: string outputXml = null;使用 (var nodeReader = new XmlNodeReader(xDoc)) { nodeReader.MoveToContent(); var original = XDocument.Load(nodeReader); string xpath = "//Person[not(PersonID = following::Person/PersonID)]"; XDocument people = new XDocument("Persons", original.XPathSelectElements(xpath)); outputXml = people.ToString(); }
  • 注意:这行得通:XDocument people = new XDocument(new XElement("Persons", original.XPathSelectElements(xpathFilterDups)));
  • @RobMcCabe:哎呀,是的,忘记将根设为显式 XElement。固定:)
【解决方案2】:

XmlDocument 可以使用

XmlDocument doc2 = new XmlDocument();
doc2.AppendChild(doc2.CreateElement("Persons"));
foreach (XmlElement person in allItems)
{
  doc2.DocumentElement.AppendChild(doc2.ImportNode(person, true));
}

【讨论】:

  • 我希望尽可能避免循环遍历每个 XmlElementNode 以提高效率。
  • 我不确定您如何建议在不读取现有文档中的所有元素的情况下从现有文档中的元素创建新文档,唯一可能很慢的部分是评估XPath 表达式。
  • 这就是发布这个问题的目的 :-) 如果可能的话。我已经在使用类似于您建议的方法。 XPath 实际上评估得相当快。我在 xml 中有超过 4000 个元素要解析,所以 for 循环真的很慢。希望避免它:-\
  • 我认为没有办法避免循环,但在 ImportNode 上使用 AppendChild 而不是 StringBuilder 和 OuterXml 应该更有效。
猜你喜欢
  • 2010-09-05
  • 1970-01-01
  • 2017-02-20
  • 1970-01-01
  • 2020-01-22
  • 1970-01-01
  • 2015-09-27
  • 2011-01-13
  • 1970-01-01
相关资源
最近更新 更多