字符串内容超过给定长度的 Xpath 最深节点 [英] Xpath deepest node whose string content is longer than a given length

查看:40
本文介绍了字符串内容超过给定长度的 Xpath 最深节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用 XPath 找到匹配字符串内容长度约束的最深节点.

给定一段如下所示的 XHTML(或 XML):

<身体><div id="页面"><div id="desc">这款羊毛衫具有以下特点:<ul><li>4 个按钮</li><li>美利奴羊毛</li>

...</html>

一个 XPath 表达式,如

///*[string-length() >50]

将匹配 、、

.如何让 XPath 选择最深的匹配节点(即:<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屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆