C# 返回每个XML文本元素的XPath

C# 返回每个XML文本元素的XPath,c#,xml,xpath,C#,Xml,Xpath,我想为以下XML中的每个文本元素返回一个XPath或类似值。 我尝试了XPathNodeIterator,但它似乎只返回指定节点级别下的节点。如何获取所有节点和子节点并返回如下所示的对象列表 String exp = "/*/*/child::*"; XPathNodeIterator NodeIter = navigator.Select(exp); XML: 头衔 特征 名字 年龄 性别 评论 账单 链接 预期结果: 我想得到一个类似于(div/p[1],Title),(div

我想为以下XML中的每个文本元素返回一个XPath或类似值。 我尝试了
XPathNodeIterator
,但它似乎只返回指定节点级别下的节点。如何获取所有节点和子节点并返回如下所示的对象列表

String exp = "/*/*/child::*";
XPathNodeIterator NodeIter = navigator.Select(exp);
XML:


头衔

  • 特征
  • 名字
  • 年龄
  • 性别
评论 账单

链接

预期结果:
我想得到一个类似于
(div/p[1],Title),(div/ul[1]/li[1],Features),(div/ul[2]/li[1],Name),(div/ul[2]/li[2],Age),(div/ul[2]/li[3],Gender),(div/h2[1],Comments),(div/p[2],Bill),(div/p[3],Link)
我找不到一个内置的方法可以为您提供所需的路径。但是我能够创建一个递归函数来完成这个任务。下面是我想出的代码:

    private void button1_Click(object sender, EventArgs e)
    {
        string xmlText = textBox1.Text;

        String exp = "//text()";
        XmlDocument xml = new XmlDocument();
        xml.LoadXml(xmlText);

        //Writes the text out to a textbox
        foreach (XmlNode x in xml.SelectNodes(exp))
            textBox2.AppendText("(" + GetPath(x) + ", " + x.InnerText + ")\n");
    }

    string GetPath(XmlNode nd)
    {
        if (nd.ParentNode != null && nd.NodeType == XmlNodeType.Text)
        {
            return GetPath(nd.ParentNode);
        }
        else if (nd.ParentNode != null && nd.NodeType != XmlNodeType.Text)
        {
            var index = nd.ParentNode.ChildNodes.Cast<XmlNode>().ToList().IndexOf(nd);
            string path = GetPath(nd.ParentNode);
            path += (path != "") ? "/" : "";
            return string.Format("{0}{1}[{2}]", path, nd.Name, index);
        }
        else return "";
    }

我看到了一个警告,因为我不知道您将使用它用于什么应用程序,但是如果您将使用它从HTML获取元素,则
LoadXML()
函数可能会中断。“有效”HTML不一定是有效的XML,加载可能会失败。

只需在.NET中运行此转换(使用XslCompiledTransform):


从那以后是XPath吗?索引从XPath的
1
开始。如果要选择不包含其他元素的元素,则应选择
/*[not(*)]
。至于生成XPath表达式,您想用XML和名称空间做什么?您想要的是
ui
而不是
ul
?我建议您试试递归,如果您有问题,回来我们会帮助您。我不确定我是否理解您的问题。是否尝试1)查找所有具有文本值的
xmlement
节点?遍历一个
XmlElement
层次结构,并为每个唯一指定它的元素生成一个XPath查询?@Chuck Savage这是一个拼写错误,应该是ul。感谢jwatts1980。你的密码起作用了。我正在修改您的解决方案,看看是否可以使用XDocument完成。谢谢Dimitre Novatchev。我测试了它,它也起作用了。
    private void button1_Click(object sender, EventArgs e)
    {
        string xmlText = textBox1.Text;

        String exp = "//text()";
        XmlDocument xml = new XmlDocument();
        xml.LoadXml(xmlText);

        //Writes the text out to a textbox
        foreach (XmlNode x in xml.SelectNodes(exp))
            textBox2.AppendText("(" + GetPath(x) + ", " + x.InnerText + ")\n");
    }

    string GetPath(XmlNode nd)
    {
        if (nd.ParentNode != null && nd.NodeType == XmlNodeType.Text)
        {
            return GetPath(nd.ParentNode);
        }
        else if (nd.ParentNode != null && nd.NodeType != XmlNodeType.Text)
        {
            var index = nd.ParentNode.ChildNodes.Cast<XmlNode>().ToList().IndexOf(nd);
            string path = GetPath(nd.ParentNode);
            path += (path != "") ? "/" : "";
            return string.Format("{0}{1}[{2}]", path, nd.Name, index);
        }
        else return "";
    }
(div[0]/p[0], Title)
(div[0]/ul[1]/li[0], Features)
(div[0]/ul[2]/li[0], Name)
(div[0]/ul[2]/li[1], Age)
(div[0]/ul[2]/li[2], Gender)
(div[0]/h2[3], Comments)
(div[0]/p[4], Bill)
(div[0]/p[5], Link)
<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:variable name="vApos">'</xsl:variable>

  <xsl:template match="text()">
     <xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
     <xsl:value-of select="concat('=',$vApos,.,$vApos)"/>
     <xsl:text>&#xA;</xsl:text>
  </xsl:template>

  <xsl:template match="*" mode="path">
    <xsl:value-of select="concat('/',name())"/>
    <xsl:variable name="vnumPrecSiblings" select=
      "count(preceding-sibling::*[name()=name(current())])"/>
    <xsl:if test="$vnumPrecSiblings or following-sibling::*[name()=name(current())]">
        <xsl:value-of select="concat('[', $vnumPrecSiblings +1, ']')"/>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>
<div>
    <p>Title</p>
    <ul>
       <li>Features</li>
    </ul>
    <p/>
    <ul>
       <li>Name</li>
       <li>Age</li>
       <li>Gender</li>
    </ul>
    <h2>Comments</h2>
    <p>Bill</p>
    <p>Link</p>
</div>
/div/p[1]='Title'
/div/ul[1]/li='Features'
/div/ul[2]/li[1]='Name'
/div/ul[2]/li[2]='Age'
/div/ul[2]/li[3]='Gender'
/div/h2='Comments'
/div/p[3]='Bill'
/div/p[4]='Link'