字符串内容超过给定长度的 Xpath 最深节点 [英] Xpath deepest node whose string content is longer than a given length
问题描述
如何使用 XPath 找到匹配字符串内容长度约束的最深节点.
给定一段如下所示的 XHTML(或 XML):
<身体><div id="页面"><div id="desc">这款羊毛衫具有以下特点:<ul><li>4 个按钮</li><li>美利奴羊毛</li>
...</html>
一个 XPath 表达式,如
///*[string-length() >50]
将匹配 、、
div id="desc">
)?加分项,如何将约束应用于空间规范化内容长度?
这不能表示为单个 XPath 1.0 表达式(不使用变量)
单个 XPath 2.0 表达式:
///*[string-length(.) >50][count(ancestor::*) >=//*[string-length(.) >50]/计数(祖先::*)]
使用变量的 XPath 1.0 表达式:
///*[string-length() >50][not(///*[字符串长度() > 50和计数(祖先::*)>$vNumAncestors])]
其中变量 vNumAncestors
保存上下文节点的 count(ancestor::*)
值.
后一个表达式可以在宿主语言中实现,例如 XSLT 1.0 或 DOM.
这是一个 XSLT 1.0 实现:
<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="vNumAncestors"选择=计数(祖先::*)"/><xsl:copy-of select="(.)[not(///*[string-length() > 50和计数(祖先::*)>$vNumAncestors])]"/></xsl:for-each></xsl:模板></xsl:stylesheet>
当此转换应用于提供的 XML 文档时:
<身体><div id="页面"><div id="desc">这款羊毛衫具有以下特点:<ul><li>4 个按钮</li><li>美利奴羊毛</li>
...</html>
产生想要的、正确的结果:
这款羊毛衫具有以下特点:<ul><li>4 个按钮</li><li>美利奴羊毛</li>
<块引用>
奖励积分,如何应用对空间规范化内容的限制长度?
在最后一个解决方案之上实现非常简单:
<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="vNumAncestors"选择=计数(祖先::*)"/><xsl:copy-of select="(.)[not(///*[string-length(normalize-space()) > 50和计数(祖先::*)>$vNumAncestors])]"/></xsl:for-each></xsl:模板></xsl:stylesheet>
并且最初的 XPath 2.0 表达式现在修改为这个:
//*[string-length(normalize-space(.)) >50][计数(祖先::*)>=//*[string-length(normalize-space(.)) >50]/计数(祖先::*)]
How does one use XPath to find the deepest node that matches a string content length constraint.
Given a chunk of XHTML (or XML) that looks like this:
<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>
An an XPath expression like
//*[string-length() > 50]
Would match the <html>, <body>, <div id="page"> and <div id="desc">
. How can one make XPath pick the deepest matching node (ie: <div id="desc">
)?
Bonus points, how does one apply the constraint to space normalized content length?
This cannot be expressed as a single XPath 1.0 expression (not using variables)
A single XPath 2.0 expression:
//*[string-length(.) > 50]
[count(ancestor::*) >= //*[string-length(.) > 50]/count(ancestor::*)]
An XPath 1.0 expression using a variable:
//*[string-length() > 50]
[not(//*[string-length() > 50
and count(ancestor::*) > $vNumAncestrors])
]
where the variable vNumAncestrors
holds the value of count(ancestor::*)
for the context node.
The latter expression can be implemented in a hosting language, such as XSLT 1.0 or DOM.
Here is one XSLT 1.0 implementation:
<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>
when this transformation is applied on the provided XML document:
<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>
the wanted, correct result is produced:
<div id="desc"> This wool sweater has the following features:
<ul>
<li>4 buttons</li>
<li>Merino Wool</li>
</ul>
</div>
Bonus points, how does one apply the constraint to space normalized content length?
Very simple to implement atop of the last solution:
<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>
And the initial XPath 2.0 expression is now modified to this one:
//*[string-length(normalize-space(.)) > 50]
[count(ancestor::*)
>=
//*[string-length(normalize-space(.)) > 50]/count(ancestor::*)
]
这篇关于字符串内容超过给定长度的 Xpath 最深节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!