在 xpath 谓词中循环遍历此序列时按顺序检索当前节点
retrieving current node in sequence when looping over this sequence in an xpath predicate
我需要转换这个输入 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>
我试过的是以下内容。但我不知道如何将序列中的当前节点(例如 'leak')传递给“显示”模板。另外,如果有比这个丑陋的匹配表达式更好的方法,请告诉我。谢谢!
<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, concat('/', $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,
concat('/', $vPart, '/')), '/'), '/')
"/>
<problem ignore="{$vIssue}"/>
</xsl:template>
<xsl:template match="problem[key('kIgnorable', generate-id())]">
<xsl:variable name="vIgnoreRule"
select="$pIgnorable/p[contains(current()/@location,
concat('/', @part, '/', 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>
我需要转换这个输入 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>
我试过的是以下内容。但我不知道如何将序列中的当前节点(例如 'leak')传递给“显示”模板。另外,如果有比这个丑陋的匹配表达式更好的方法,请告诉我。谢谢!
<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, concat('/', $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,
concat('/', $vPart, '/')), '/'), '/')
"/>
<problem ignore="{$vIssue}"/>
</xsl:template>
<xsl:template match="problem[key('kIgnorable', generate-id())]">
<xsl:variable name="vIgnoreRule"
select="$pIgnorable/p[contains(current()/@location,
concat('/', @part, '/', 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>