在 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>