C# 返回每个XML文本元素的XPath
我想为以下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
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>
</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'