我想为以下XML中的每个文本元素返回XPath或类似内容。
我尝试了XPathNodeIterator
,但似乎只返回指定节点级别下的节点。如何获取所有节点和子节点并返回如下所示的对象列表?
String exp = "/*/*/child::*";
XPathNodeIterator NodeIter = navigator.Select(exp);
XML:
<div>
<p>Title</p>
<ul>
<li>Features</li>
</ul>
<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[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)
答案 0 :(得分:1)
我无法找到能够为您提供所需路径的内置方法。但是我能够创建一个可以完成这个技巧的递归函数。这是我提出的代码:
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 "";
}
我在Form
上测试它,因此按下了按钮点击事件。使用//text()
获取所有文本节点非常简单。提出一个递归函数来构建路径比我预期的要困难一些。通过将ParentNode.ChildNodes
转换为XmlNode
的集合,然后转换为列表,我们可以使用IndexOf()
的{{1}}方法来获取这一点索引。
结果:
List
我看到了一个警告,因为我不知道你将使用它的应用程序,但是如果你打算使用它来从HTML获取元素,那么(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)
功能可能会破裂。 &#34;有效&#34; HTML不一定是有效的XML,加载可能会失败。
答案 1 :(得分:1)
只需在.NET中运行此转换(使用XslCompiledTransform):
<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>
</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>
应用于提供的源XML文档:
<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'