获得XElement的InnerXml的最佳方法是什么?

Mik*_*ell 144 .net xml xelement innerxml

body在下面的代码中获取混合元素内容的最佳方法是什么?该元素可能包含XHTML或文本,但我只想要其字符串形式的内容.该XmlElement类型具有InnerXml我正在追求的属性.

编写的代码几乎可以实现我想要的功能,但包含了我不想要的周围的<body>... </body>元素.

XDocument doc = XDocument.Load(new StreamReader(s));
var templates = from t in doc.Descendants("template")
                where t.Attribute("name").Value == templateName
                select new
                {
                   Subject = t.Element("subject").Value,
                   Body = t.Element("body").ToString()
                };
Run Code Online (Sandbox Code Playgroud)

Luk*_*son 204

我想看看哪些建议的解决方案表现最好,所以我进行了一些比较测试.出于兴趣,我还将LINQ方法与Greg建议的普通的System.Xml方法进行了比较.变化很有趣,而不是我的预期,最慢的方法比最快的方法慢3倍.

结果以最快到最慢排序:

  1. CreateReader - Instance Hunter(0.113秒)
  2. 普通的旧System.Xml - Greg Hurlman(0.134秒)
  3. 与字符串连接聚合 - Mike Powell(0.324秒)
  4. StringBuilder - Vin(0.333秒)
  5. String.Join阵列 - 特里(0.360秒)
  6. 数组上的String.Concat - Marcin Kosieradzki(0.364)

方法

我使用了一个包含20个相同节点的XML文档(称为"提示"):

<hint>
  <strong>Thinking of using a fake address?</strong>
  <br />
  Please don't. If we can't verify your address we might just
  have to reject your application.
</hint>
Run Code Online (Sandbox Code Playgroud)

以秒为单位显示的数字是提取20个节点的"内部XML",连续1000次,并取5次运行的平均值(平均值)的结果.我没有包括将XML加载和解析为XmlDocument(对于System.Xml方法)或XDocument(对于所有其他方法)所花费的时间.

我使用的LINQ算法是:(C# - 全部采用XElement"父"并返回内部XML字符串)

CreateReader:

var reader = parent.CreateReader();
reader.MoveToContent();

return reader.ReadInnerXml();
Run Code Online (Sandbox Code Playgroud)

使用字符串连接进行聚合:

return parent.Nodes().Aggregate("", (b, node) => b += node.ToString());
Run Code Online (Sandbox Code Playgroud)

StringBuilder的:

StringBuilder sb = new StringBuilder();

foreach(var node in parent.Nodes()) {
    sb.Append(node.ToString());
}

return sb.ToString();
Run Code Online (Sandbox Code Playgroud)

String.Join数组:

return String.Join("", parent.Nodes().Select(x => x.ToString()).ToArray());
Run Code Online (Sandbox Code Playgroud)

数组上的String.Concat:

return String.Concat(parent.Nodes().Select(x => x.ToString()).ToArray());
Run Code Online (Sandbox Code Playgroud)

我没有在这里显示"Plain old System.Xml"算法,因为它只是在节点上调用.InnerXml.


结论

如果性能很重要(例如大量的XML,经常解析),我每次都会使用Daniel的CreateReader方法.如果你只是做了一些查询,你可能想要使用Mike更简洁的Aggregate方法.

如果您在具有大量节点(可能是100个)的大型元素上使用XML,您可能会开始看到使用StringBuilderAggregate方法的好处,但还没有结束CreateReader.我不认为这些条件JoinConcat方法在这些条件下会更有效率,因为将大型列表转换为大型数组会受到惩罚(在这里使用较小的列表时甚至很明显).

  • 哇,有趣的东西.感谢您花时间运行这些! (12认同)
  • 你错过了`parent.CreateNavigator().InnerXml`(需要`使用System.Xml.XPath`作为扩展方法). (7认同)
  • 你真的应该将 `var reader = parent.CreateReader();` 包装在 using 语句中。 (2认同)

Ins*_*ter 69

我认为这是一个更好的方法(在VB中,不应该难以翻译):

给定XElement x:

Dim xReader = x.CreateReader
xReader.MoveToContent
xReader.ReadInnerXml
Run Code Online (Sandbox Code Playgroud)

  • 这个小代码片段非常有用,这应该是公认的答案. (4认同)
  • XmlReader是一次性的,所以不要忘记用它包装它,请(如果我认识VB,我会自己编辑答案). (4认同)

Vin*_*Vin 18

如何在XElement上使用这个"扩展"方法?为我工作!

public static string InnerXml(this XElement element)
{
    StringBuilder innerXml = new StringBuilder();

    foreach (XNode node in element.Nodes())
    {
        // append node's xml string to innerXml
        innerXml.Append(node.ToString());
    }

    return innerXml.ToString();
}
Run Code Online (Sandbox Code Playgroud)

或者使用一点Linq

public static string InnerXml(this XElement element)
{
    StringBuilder innerXml = new StringBuilder();
    doc.Nodes().ToList().ForEach( node => innerXml.Append(node.ToString()));

    return innerXml.ToString();
}
Run Code Online (Sandbox Code Playgroud)

注意:上面的代码必须使用element.Nodes()而不是element.Elements().记住两者之间的区别非常重要.element.Nodes()给你一些像XText,XAttribute等等,但XElement只有一个元素.


Tod*_*ier 14

对于那些发现并证明是最佳方法的人(谢谢!),我们完全归功于它,这里包含了一个扩展方法:

public static string InnerXml(this XNode node) {
    using (var reader = node.CreateReader()) {
        reader.MoveToContent();
        return reader.ReadInnerXml();
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 10

保持简单高效:

String.Concat(node.Nodes().Select(x => x.ToString()).ToArray())
Run Code Online (Sandbox Code Playgroud)
  • 在连接字符串时,聚合是内存和性能低效
  • 使用Join("",sth)使用比Concat大两倍的字符串数组......在代码中看起来很奇怪.
  • 使用+ =看起来非常奇怪,但显然不比使用'+'差 - 可能会针对相同的代码进行优化,因为分配结果未使用,可能会被编译器安全删除.
  • StringBuilder是如此迫切 - 每个人都知道不必要的"状态"很糟糕.


Mik*_*ell 7

我最终使用了这个:

Body = t.Element("body").Nodes().Aggregate("", (b, node) => b += node.ToString());
Run Code Online (Sandbox Code Playgroud)