获取 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()
                };
请先 登录 后评论

8 个回答

Vin

在 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();
}

或者使用一点 Linq

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

    return innerXml.ToString();
}

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

请先 登录 后评论
Ayyash

你知道吗?最好的办法是回到 CDATA :( 我在这里寻找解决方案,但我认为 CDATA 是迄今为止最简单和最便宜的,而不是最方便的开发

请先 登录 后评论
Marcin Kosieradzki

保持简单高效:

String.Concat(node.Nodes().Select(x => x.ToString()).ToArray())
  • 聚合在连接字符串时内存和性能效率低下
  • 使用 Join(", sth) 使用的是比 Concat 大两倍的字符串数组......而且在代码中看起来很奇怪。
  • 使用 = 看起来很奇怪,但显然并不比使用“ ”差多少 - 可能会针对相同的代码进行优化,因为分配结果未使用并且可能会被编译器安全删除。
  • StringBuilder 非常必要 - 每个人都知道不必要的“状态”很糟糕。
请先 登录 后评论
Martin R-L

就个人而言,我最终使用 Aggregate 方法编写了一个 InnerXml 扩展方法:

public static string InnerXml(this XElement thiz)
{
   return thiz.Nodes().Aggregate( string.Empty, ( element, node ) => element += node.ToString() );
}

我的客户端代码就像使用旧的 System.Xml 命名空间一样简洁:

var innerXml = myXElement.InnerXml();
请先 登录 后评论
Luke Sampson

我想看看这些建议的解决方案中哪一个表现最好,所以我进行了一些比较测试。出于兴趣,我还将 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 on array - Terry(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>

上面显示的秒数是提取 20 个节点的“内部 XML”,连续 1000 次,并取 5 次运行的平均值(平均值)的结果。我没有包括将 XML 加载和解析为 XmlDocument(对于 System.Xml 方法)或 XDocument(对于所有其他人)。

我使用的 LINQ 算法是:(C

请先 登录 后评论
Mike Powell

@Greg:看来您已将答案编辑为完全不同的答案。我的回答是肯定的,我可以使用 System.Xml 来做到这一点,但我希望能用 LINQ to XML 搞定。

我将在下面留下我的原始回复,以防其他人想知道为什么我不能只使用 XElement 的 .Value 属性来获取我需要的内容:

@Greg:Value 属性连接任何子节点的所有文本内容。因此,如果 body 元素仅包含文本,它可以工作,但如果它包含 XHTML,我会将所有文本连接在一起,但没有任何标签。

请先 登录 后评论
Instance Hunter

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

给定一个 XElement x:

Dim xReader = x.CreateReader
xReader.MoveToContent
xReader.ReadInnerXml
请先 登录 后评论
Greg Hurlman

是否可以使用 System.Xml 命名空间对象来完成这里的工作而不是使用 LINQ?正如您已经提到的,XmlNode.InnerXml 正是您所需要的。

请先 登录 后评论
  • 11 关注
  • 0 收藏,290 浏览
  • Mike Powell 提出于 2019-03-29 12:09