Featured post
xml - Xpath deepest node whose string content is longer than a given length -
how 1 use xpath find deepest node matches string content length constraint.
given chunk of xhtml (or xml) looks this:
<html> <body> <div id="page"> <div id="desc"> wool sweater has following features: <ul> <li>4 buttons</li> <li>merino wool</li> </ul> </div> </div> ... </body> </html>
an xpath expression like
//*[string-length() > 50]
would match <html>, <body>, <div id="page"> , <div id="desc">
. how can 1 make xpath pick deepest matching node (ie: <div id="desc">
)?
bonus points, how 1 apply constraint space normalized content length?
this cannot expressed 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 variable:
//*[string-length() > 50] [not(//*[string-length() > 50 , count(ancestor::*) > $vnumancestrors]) ]
where variable vnumancestrors
holds value of count(ancestor::*)
context node.
the latter expression can implemented in hosting language, such xslt 1.0 or dom.
here 1 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 , count(ancestor::*) > $vnumancestrors]) ] "/> </xsl:for-each> </xsl:template> </xsl:stylesheet>
when transformation applied on provided xml document:
<html> <body> <div id="page"> <div id="desc"> wool sweater has following features: <ul> <li>4 buttons</li> <li>merino wool</li> </ul> </div> </div> ... </body> </html>
the wanted, correct result produced:
<div id="desc"> wool sweater has following features: <ul> <li>4 buttons</li> <li>merino wool</li> </ul> </div>
bonus points, how 1 apply constraint space normalized content length?
very simple implement atop of 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 , count(ancestor::*) > $vnumancestrors]) ] "/> </xsl:for-each> </xsl:template> </xsl:stylesheet>
and initial xpath 2.0 expression modified one:
//*[string-length(normalize-space(.)) > 50] [count(ancestor::*) >= //*[string-length(normalize-space(.)) > 50]/count(ancestor::*) ]
- Get link
- X
- Other Apps
Comments
Post a Comment