使用XSLT Apply-Templates有条件地选择节点

Mse*_*enb 8 xml xslt xpath

假设我有一个像这样的xml文档:

<director>
    <play>
        <t>Nutcracker</t>
        <a>Tom Cruise</a>
    </play>
    <play>
        <t>Nutcracker</t>
        <a>Robin Williams</a>
    </play>
    <play>
        <t>Grinch Stole Christmas</t>
        <a>Will Smith</a>
    </play>
    <play>
        <t>Grinch Stole Christmas</t>
        <a>Mel Gibson</a>
    </play>
</director>
Run Code Online (Sandbox Code Playgroud)

现在我希望能够选择Will Smith作为演员的所有剧本并将其重新格式化为如下:

<Plays>
    <Play title="Grinch Stole Christmas">
       <star>Will Smith</star>
       <star>Mel Gibson</star>
    </Play>
</Plays>
Run Code Online (Sandbox Code Playgroud)

我只想使用apply-templates ..没有xsl:if或者每个循环(我把这个例子设想为我正在做的更简单的版本,所以你可以帮我理解如何在匹配语句中使用xpath)

这是我到目前为止:

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
        <xsl:template match="/director">
                <Plays>
                <xsl:apply-templates select="play"/>
                </Plays>
        </xsl:template>

        <xsl:template match="play[a='Will Smith']">
                <play title="{data(t)[1]}">
                <xsl:apply-templates select="a"/>
                </play>
        </xsl:template>

        <xsl:template match="a">
                <star>
                <xsl:value-of select="."/>
                </star>
        </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

基本上我只是不确定如何在模板的match属性中使用XPath过滤掉节点.任何帮助都会很棒!

cka*_*ras 9

条件应该是xsl:apply-templates而不是xsl:template:

<Plays>
  <xsl:apply-templates select="play[a='Will Smith']">"/>
</Plays>
Run Code Online (Sandbox Code Playgroud)

在您的解决方案中,您正在转换所有<play>节点.对于与条件匹配的播放节点,将应用您的模板.但对于那些与条件不匹配的人,则应用默认模板("身份转换").

或者,您可以将条件保持在xsl:template match,但为<play>添加另一个与条件不匹配的模板,将这些<play>转换为空:

    <xsl:template match="play[a='Will Smith']">
      <play title="{data(t)[1]}">
        <xsl:apply-templates select="a"/>
      </play>
    </xsl:template>

    <xsl:template match="play">
    </xsl:template>
Run Code Online (Sandbox Code Playgroud)


Dim*_*hev 5

I.可能是效率最高的XSLT 1.0解决方案:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kWSPlayByTitle" match="play[a='Will Smith']"
  use="t"/>

 <xsl:key name="kActorByTitle" match="a"
  use="../t"/>

 <xsl:template match="/">
  <Plays>
    <xsl:apply-templates select=
    "*/play[generate-id()
           =
            generate-id(key('kWSPlayByTitle',t)[1])
           ]"/>
  </Plays>
 </xsl:template>

 <xsl:template match="play">
  <Play title="{t}">
   <xsl:apply-templates select="key('kActorByTitle',t)"/>
  </Play>
 </xsl:template>

 <xsl:template match="a">
  <star><xsl:value-of select="."/></star>
 </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

当此转换应用于提供的XML文档时:

<director>
    <play>
        <t>Nutcracker</t>
        <a>Tom Cruise</a>
    </play>
    <play>
        <t>Nutcracker</t>
        <a>Robin Williams</a>
    </play>
    <play>
        <t>Grinch Stole Christmas</t>
        <a>Will Smith</a>
    </play>
    <play>
        <t>Grinch Stole Christmas</t>
        <a>Mel Gibson</a>
    </play>
</director>
Run Code Online (Sandbox Code Playgroud)

产生了想要的结果:

<Plays>
   <Play title="Grinch Stole Christmas">
      <star>Will Smith</star>
      <star>Mel Gibson</star>
   </Play>
</Plays>
Run Code Online (Sandbox Code Playgroud)

请注意:

  1. 通过使用 Mell Gibson参与的所有戏剧以及参与特定(标题)戏剧的所有演员的关键来实现效率.

  2. 即使梅尔吉布森的比赛名称不止一次被列出(由于意外错误,也许......),它将仅在结果中列出一次.

II.一个简单而有效的XSLT 2.0解决方案:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/*">
  <Plays>
    <xsl:for-each-group select="play[a='Mel Gibson']"
          group-by="t">
      <xsl:apply-templates select="."/>
    </xsl:for-each-group>
  </Plays>
 </xsl:template>

 <xsl:template match="play">
  <Play title="{t}">
   <xsl:for-each-group select="../play[t = current()/t]/a"
        group-by=".">
     <xsl:apply-templates select="."/>
   </xsl:for-each-group>
  </Play>
 </xsl:template>

 <xsl:template match="a">
  <star>
    <xsl:value-of select="."/>
  </star>
 </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)