代码之家  ›  专栏  ›  技术社区  ›  Msencenb

使用XSLT将模板应用于条件选择节点

  •  9
  • Msencenb  · 技术社区  · 15 年前

    假设我有这样一个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>
    

    <Plays>
        <Play title="Grinch Stole Christmas">
           <star>Will Smith</star>
           <star>Mel Gibson</star>
        </Play>
    </Plays>
    

    我只想使用应用模板。。没有xsl:if或for-each循环(我把这个例子设计成一个更简单的版本,这样您就可以帮助我理解如何在match语句中使用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>
    

    3 回复  |  直到 15 年前
        1
  •  9
  •   ckarras    15 年前

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

    <Plays>
      <xsl:apply-templates select="play[a='Will Smith']">"/>
    </Plays>
    

    在您的解决方案中,您正在转换所有“播放”节点。 对于符合条件的播放节点,将应用模板。但对于那些不符合条件的模板,将应用默认模板(“identity transform”)。

    或者,可以在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>
    
        2
  •  5
  •   Dimitre Novatchev    15 年前

    一、 可能是最有效的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>
    

    当此转换应用于所提供的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>
    

    得到想要的结果

    <Plays>
       <Play title="Grinch Stole Christmas">
          <star>Will Smith</star>
          <star>Mel Gibson</star>
       </Play>
    </Plays>
    

    做笔记 :

    1. 无论是梅尔吉布森参与的所有剧目,还是参与给定(标题)剧目的所有演员。

    2. 即使梅尔吉布森的一个游戏标题被列了不止一次(可能是由于偶然的错误……),它也只会在结果中列一次 .

    二。一个简单高效的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>
    
        3
  •  1
  •   user357812 user357812    15 年前

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:key name="kActorByTitle" match="a" use="../t"/>
        <xsl:param name="pActor" select="'Will Smith'"/>
        <xsl:template match="/">
            <Plays>
                <xsl:apply-templates select="*/play[a=$pActor]"/>
            </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>
    

    输出:

    <Plays>
        <Play title="Grinch Stole Christmas">
            <star>Will Smith</star>
            <star>Mel Gibson</star>
        </Play>
    </Plays>