【问题标题】:XmlNode.InnerTextXmlNode.InnerText
【发布时间】:2011-01-17 15:38:27
【问题描述】:

我们有这样的 XML:

<Example>
  <Node>Some text here
    <ChildNode>Child 1</ChildNode>
    <ChildNode>Child 2</ChildNode>
  </Node>
</Example>

我们正在使用XmlDocument 来解析这个。

当我们拥有“Node”元素的 XmlNode 时,XmlNode.InnerText 会返回:

"Some text hereChild 1Child2"

我们如何在没有子节点的内部文本的情况下获取 Node 元素的内部文本?我们真的不想使用任何 RegEx 或字符串拆分来完成此操作。

注意:我们也不想切换到使用一组不同的类来解析这个 XML,这将是太多的代码更改。

【问题讨论】:

    标签: c# .net xml


    【解决方案1】:
    var doc = new XmlDocument();
    doc.LoadXml(xml);
    var text = doc.SelectSingleNode("Example/Node/text()").InnerText; // or .Value
    

    返回

    "Some text here\r\n    "
    

    text.Trim() 返回

    "Some text here"
    

    【讨论】:

    • 试试这个:node.SelectSingleNode("text()").InnerText.Trim()
    • @Jonathan:是的,也一样,我只是想给你看一些内在的过程
    • @Jonathan: jfyi,你可以使用波浪线在评论中高亮代码:node.SelectSingleNode("text()").InnerText.Trim()
    【解决方案2】:

    怎么样:

    XmlDocument d=new XmlDocument();
    d.LoadXml(@"<Example>
      <Node>Some text here
        <ChildNode>Child 1</ChildNode>
        <ChildNode>Child 2</ChildNode>
      </Node>
    </Example>");
    var textNodeValues=d.DocumentElement
        .FirstChild
        .ChildNodes
        .Cast<XmlNode>()
        .Where(x=>x.NodeType==XmlNodeType.Text)
        .Select(x=>x.Value);
    

    【讨论】:

    • FirstOrDefault(x=&gt;x.NodeType==XmlNodeType.Text) 更适合这种情况,我猜。不是吗?
    • @Abatishchev:直接回答这个问题,你是对的,但是 OP 没有指定在其他文本节点存在的情况下的行为。反正我更喜欢你的 Xpath。
    【解决方案3】:

    你可以像这样实现:

        XmlDocument doc = new XmlDocument();
        doc.LoadXml("<Example><Node>Some text here<ChildNode>Child 1</ChildNode><ChildNode>Child 2</ChildNode></Node></Example>");
        XmlNode node = doc.SelectSingleNode( "Example/Node" );
        if (node.HasChildNodes)
        {
            string value = node.FirstChild.Value;
        }
    

    【讨论】:

      【解决方案4】:

      据我所知,没有直接的方法可以做到这一点。您必须遍历子文本节点并自己构建连接文本:

      using System.Text;
      using System.Xml;
      
      public string GetImmediateInnerText(XmlNode node)
      {
          StringBuilder builder = new StringBuilder();
          foreach (XmlNode child in node.ChildNodes) {
              if (child.NodeType == XmlNodeType.Text) {
                  builder.Append(child.Value);
              }
          }
          return builder.ToString();
      }
      

      您也可以像@abatishchev 那样使用text() XPath 表达式:

      public string GetImmediateInnerText(XmlNode node)
      {
          StringBuilder builder = new StringBuilder();
          foreach (XmlNode child in node.SelectNodes("text()")) {
              builder.Append(child.Value);
          }
          return builder.ToString();
      }
      

      【讨论】:

      • 确实有:text()XPath函数
      • @abatishchev,是的,但是你需要使用SelectNodes()而不是SelectSingleNode(),否则你只会返回元素的第一个子文本节点:)
      • 是的,我试过了,你是对的。但我认为在子节点之后存在某些文本的情况非常罕见。 IMO 文本存在之前,子节点也很少。还有一种解决方法:doc.SelectNodes("../text()").Cast&lt;XmlNode&gt;().Select(n=&gt;n.InnerText.Trim())等。
      • @abat:你需要检查一下:meta.stackexchange.com/questions/75250/…
      • @Hans:谢谢!我会考虑的,当然。