如何解决在 xpath 谓词中循环此序列时按顺序检索当前节点
我需要转换这个输入的xml:
<Problems>
<problem location="engineroom/boiler/nozzle"/>
<problem location="engineroom/boiler/nozzle/leak"/>
<problem location="office/printer/paper"/>
<problem location="office/printer/paper/empty/A4"/>
<problem location="office/printer/paper/empty/A3"/>
<problem location="garage/truck/window"/>
<problem location="garage/truck/window/crack"/>
</Problems>
到这个输出xml:
<Problems>
<problem ignore="leak"/>
<problem ignore="leak"/>
<problem ignore="empty"/>
<problem ignore="empty"/>
<problem ignore="empty"/>
<problem location="garage/truck/window"/>
<problem location="garage/truck/window/crack"/>
</Problems>
我当前的代码涉及对感兴趣的项目('leak'、'empty')及其父元素('nozzle'、'paper')进行硬编码:
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="problem[contains(@location,'leak')]
| problem[ends-with(@location,'nozzle')][contains(following-sibling::problem[1]/@location,'nozzle/leak')]">
<xsl:apply-templates select="." mode="display">
<xsl:with-param name="location" select="'leak'"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="problem[contains(@location,'empty')]
| problem[ends-with(@location,'paper')][contains(following-sibling::problem[1]/@location,'paper/empty')]">
<xsl:apply-templates select="." mode="display">
<xsl:with-param name="location" select="'empty'"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="problem[contains(@location,'burnt')]
| problem[ends-with(@location,'PCB')][contains(following-sibling::problem[1]/@location,'PCB/burnt')]">
<xsl:apply-templates select="." mode="display">
<xsl:with-param name="location" select="'burnt'"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="problem" mode="display">
<xsl:param name="location"/>
<problem ignore="{$location}"/>
</xsl:template>
我尝试过的如下。但我不知道如何将序列中的当前节点(例如“泄漏”)传递给“显示”模板。另外,请让我知道是否有比这个丑陋的匹配表达式更好的方法。谢谢!
<xsl:variable name="issues">
<issue name="leak" parent="nozzle"/>
<issue name="empty" parent="paper"/>
<issue name="burnt" parent="PCB"/>
</xsl:variable>
<xsl:template match="problem[true() = (for $i in $issues/issue return if(
contains(@location,$i/@name)
or ends-with(@location,$i/parent) and contains(following-sibling::problem[1]/@location,$i/@name)
) then true() else false())]">
<xsl:apply-templates select="." mode="display">
<xsl:with-param name="location" select="'???'"/>
</xsl:apply-templates>
</xsl:template>
解决方法
我不确定我是否理解了这个问题,但所提供的算法似乎可以在 XSLT 3 中实现为
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
exclude-result-prefixes="#all"
version="3.0">
<xsl:param name="relations" as="map(xs:string,xs:string)"
select="map { 'leak' : 'nozzle','empty' : 'paper' }"/>
<xsl:variable name="relation-keys" select="map:keys($relations)"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="problem[some $key in $relation-keys satisfies contains(@location,$key)]">
<xsl:apply-templates select="." mode="display">
<xsl:with-param name="location" select="$relation-keys[contains(current()/@location,.)]"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="problem[some $key in $relation-keys
satisfies (ends-with(@location,$relations($key)) and contains(following-sibling::problem[1]/@location,$key))]">
<xsl:apply-templates select="." mode="display">
<xsl:with-param name="location" select="$relation-keys[ends-with(current()/@location,$relations(.)) and contains(current()/following-sibling::problem[1]/@location,.)]"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="problem" mode="display">
<xsl:param name="location"/>
<problem ignore="{$location}"/>
</xsl:template>
</xsl:stylesheet>
,
这个 XSLT 2.0 转换:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kIgnorable" match="problem" use=
"generate-id(current())
[$pIgnorable/p[contains(current()/@location,concat('/',@part,'/',issue))]]"/>
<xsl:param name="pIgnorable">
<p part="nozzle">
<issue>leak</issue>
</p>
<p part="paper">
<issue>empty</issue>
</p>
<p part="PCB">
<issue>burnt</issue>
</p>
</xsl:param>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="problem
[
for $part in tokenize(@location,'/')[last()][. = $pIgnorable/p/@part],$issue in $pIgnorable/p[@part = $part]/issue
return
following-sibling::problem[1]
[
contains(@location,$part,$issue))
]
]">
<xsl:variable name="vPart" select="tokenize(@location,'/')[last()]"/>
<xsl:variable name="vIssue" select=
"substring-before(concat(following-sibling::problem[1]
/substring-after(@location,$vPart,'/')),'/'),'/')
"/>
<problem ignore="{$vIssue}"/>
</xsl:template>
<xsl:template match="problem[key('kIgnorable',generate-id())]">
<xsl:variable name="vIgnoreRule"
select="$pIgnorable/p[contains(current()/@location,issue))]"/>
<problem ignore="{$vIgnoreRule/issue}"/>
</xsl:template>
</xsl:stylesheet>
应用于提供的 XML 文档时:
<Problems>
<problem location="engineroom/boiler/nozzle"/>
<problem location="engineroom/boiler/nozzle/leak"/>
<problem location="office/printer/paper"/>
<problem location="office/printer/paper/empty/A4"/>
<problem location="office/printer/paper/empty/A3"/>
<problem location="garage/truck/window"/>
<problem location="garage/truck/window/crack"/>
</Problems>
产生想要的、正确的结果:
<Problems>
<problem ignore="leak"/>
<problem ignore="leak"/>
<problem ignore="empty"/>
<problem ignore="empty"/>
<problem ignore="empty"/>
<problem location="garage/truck/window"/>
<problem location="garage/truck/window/crack"/>
</Problems>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。