背景 我有一个XML文档,其结构如下:
<body>
<section>content</section>
<section>content</section>
<section>content</section>
<section>content</section>
</body>
使用xpath我想检查<section>
元素是否是第二个元素,如果是,则应用某个函数。
问题:
如何检查<section>
元素是否是body元素中的第二个元素?
../section[position()=2]
答案 0 :(得分:0)
问题:如何检查元素是否是第二个元素 在身体元素?
使用C#,您可以使用XPathNodeIterator
类来遍历节点数据,并使用其CurrentPosition
属性来调查当前节点位置:
XPathNodeIterator.CurrentPosition
示例:
const string xmlStr = @"<body>
<section>1</section>
<section>2</section>
<section>3</section>
<section>4</section>
</body>";
using (var stream = new StringReader(xmlStr))
{
var document = new XPathDocument(stream);
XPathNavigator navigator = document.CreateNavigator();
XPathNodeIterator nodes = navigator.Select("/body/section");
if (nodes.MoveNext())
{
XPathNavigator nodesNavigator = nodes.Current;
XPathNodeIterator nodesText =
nodesNavigator.SelectDescendants(XPathNodeType.Text, false);
while (nodesText.MoveNext())
{
if (nodesText.CurrentPosition == 2)
{
//DO SOMETHING WITH THE VALUE AT THIS POSITION
var currentValue = nodesText.Current.Value;
}
}
}
}
答案 1 :(得分:0)
如果您想知道body
中的第二个元素是否被命名为section
,那么您可以这样做:
local-name(/body/child::element()[2]) eq "section"
这将返回true
或false
。
然而,您随后询问如何检查此问题以及是否为true
,然后应用某些功能。在XPath中,您无法创建自己的函数,只能在XQuery或XSLT中执行此操作。因此,请假设您希望在第二个元素的值为section
时调用不同的XPath函数。以下是应用lower-case
函数的示例:
if(local-name(/body/child::element()[2]) eq "section")then
lower-case(/body/child::element()[2])
else()
然而,这可以简化,因为小写和许多其他函数采用最小基数为零的值。这意味着您可以将函数应用于路径表达式,如果路径与任何内容都不匹配,则函数通常返回空序列,其方式与不匹配的路径相同。所以,这在语义上等同于上面的内容:
lower-case(/body/child::element()[2][local-name(.) eq "section"])
如果您使用XQuery或XSLT并且正在编写自己的函数,我建议您编写接受最小基数为零的函数,就像lower-case
一样。通过这样做,您可以将函数链接在一起,如果没有输入数据(即来自路径表达式不匹配任何东西),这些都不是输出数据。这导致了一种非常好的函数式编程风格。