如何使用XPath查找与字符串内容长度约束匹配的最深节点。
给出一大块XHTML(或XML),如下所示:
<html>
<body>
<div id="page">
<div id="desc">
This wool sweater has the following features:
<ul>
<li>4 buttons</li>
<li>Merino Wool</li>
</ul>
</div>
</div>
...
</body>
</html>
像
这样的XPath表达式//*[string-length() > 50]
会匹配<html>, <body>, <div id="page"> and <div id="desc">
。如何让XPath选择最深的匹配节点(即:&lt; div id="desc">
)?
奖励积分,如何将约束应用于空间规范化内容长度?
答案 0 :(得分:3)
这不能表示为单个XPath 1.0表达式(不使用变量)
单个XPath 2.0表达式:
//*[string-length(.) > 50]
[count(ancestor::*) >= //*[string-length(.) > 50]/count(ancestor::*)]
使用变量:
的XPath 1.0表达式//*[string-length() > 50]
[not(//*[string-length() > 50
and count(ancestor::*) > $vNumAncestrors])
]
其中变量vNumAncestrors
保存上下文节点的count(ancestor::*)
值。
后一种表达式可以用托管语言实现,例如XSLT 1.0或DOM。
这是一个XSLT 1.0实现:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<xsl:variable name="vLongTextElements"
select="//*[string-length()>50]"/>
<xsl:for-each select="$vLongTextElements">
<xsl:variable name="vNumAncestrors"
select="count(ancestor::*)"/>
<xsl:copy-of select=
"(.)[not(//*[string-length() > 50
and count(ancestor::*) > $vNumAncestrors])
]
"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
将此转换应用于提供的XML文档:
<html>
<body>
<div id="page">
<div id="desc"> This wool sweater has the following features:
<ul>
<li>4 buttons</li>
<li>Merino Wool</li>
</ul>
</div>
</div> ...
</body>
</html>
产生了想要的正确结果:
<div id="desc"> This wool sweater has the following features:
<ul>
<li>4 buttons</li>
<li>Merino Wool</li>
</ul>
</div>
奖励积分,如何应用 空间规范化内容的约束 长度?
在最后一个解决方案的顶部实现非常简单:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<xsl:variable name="vLongTextElements"
select="//*[string-length(normalize-space())>50]"/>
<xsl:for-each select="$vLongTextElements">
<xsl:variable name="vNumAncestrors"
select="count(ancestor::*)"/>
<xsl:copy-of select=
"(.)[not(//*[string-length(normalize-space()) > 50
and count(ancestor::*) > $vNumAncestrors])
]
"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
现在,最初的XPath 2.0表达式已修改为:
//*[string-length(normalize-space(.)) > 50]
[count(ancestor::*)
>=
//*[string-length(normalize-space(.)) > 50]/count(ancestor::*)
]
答案 1 :(得分:2)
正如Dimitre指出的那样,在XPath 1.0中解决这个问题的问题是最大表达式仅适用于未计算的值:
$node-set[not($node-set/node-or-attribute > node-or-attribute)]
这就是为什么在XSLT 1.0中你会使用“标准”最大结构:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="//*[string-length(normalize-space())>50]">
<xsl:sort select="count(ancestor::*)"
data-type="number" order="descending"/>
<xsl:if test="position()=1">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
输出:
<div id="desc"> This wool sweater has the following features:
<ul>
<li>4 buttons</li>
<li>Merino Wool</li>
</ul>
</div>