XSLT Match属性,然后是其元素

时间:2012-03-31 03:02:58

标签: xslt

在我的源XML中,任何元素都可以具有@n属性。如果有的话,我想在处理元素及其所有子元素之前输出

例如

<line n="2">Ipsum lorem</line>
<verse n="5">The sounds of silence</verse>
<verse>Four score and seven</verse>
<sentence n="3">
    <word n="1">Hello</word>
    <word n="2">world</word>
</sentence>

我的模板与“line”,“verse”,“sentence”和“word”匹配。如果这些元素中的任何一个具有@n值,我想在元素模板生成的任何内容之前输出它。

以上可能会出现类似

的内容
2 <div class="line">Ipsum lorem</span>
5 <span class="verse">The sounds of silence</span>
<span class="verse">Four score and seven</span>
3 <p class="sentence">
   1 <span class="word">Hello</span>
   2 <span class="word">world</span>
  </p>

其中“line”,“verse”等模板生成了div,span和p元素。

我该如何看待这个问题? - 匹配属性,然后将模板应用于其父项? (它的语法是什么?)在每个元素的模板的开头放一个调用模板? (那没什么吸引力。)还有别的吗? (可能!)

我尝试了一些东西,但是得到了一个无限循环,或者什么都没有,或者处理属性然后是它的父亲的子节点,而不是父节点本身。

2 个答案:

答案 0 :(得分:3)

为简化问题,我将XML中的映射放置在文档内数据结构中(可通过document()函数访问,无需参数)。现在只需要一个模板,只需要在一个地方对@n属性进行特殊处理。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html"/>

  <map>
    <elt xml="line" html="class"/>
    <elt xml="verse" html="span"/>
    <elt xml="sentence" html="p"/>
    <elt xml="word" html="span"/>
  </map>

  <xsl:template match="line|verse|sentence|word">
    <xsl:if test="@n"><xsl:value-of select="@n"/> </xsl:if>
    <xsl:element name="{document()/map/elt[@xml=name()]/@html}">
      <xsl:attribute name="class"><xsl:value-of select="name()"/></xsl:attibute>
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>

答案 1 :(得分:1)

以下是一种简单的方法

<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:template match="*/*[@n]">
  <xsl:value-of select="concat('&#xA;', @n, ' ')"/>

  <xsl:apply-templates select="self::*" mode="content"/>
 </xsl:template>

 <xsl:template match="*/*[not(@*)]">
  <xsl:apply-templates select="." mode="content"/>
 </xsl:template>

 <xsl:template match="line" mode="content">
  <div class="line"><xsl:apply-templates/></div>
 </xsl:template>

 <xsl:template match="verse | word" mode="content">
  <span class="{name()}"><xsl:apply-templates mode="content"/></span>
 </xsl:template>

 <xsl:template match="sentence" mode="content">
  <p class="sentence"><xsl:apply-templates/></p>
 </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时:

<t>
    <line n="2">Ipsum lorem</line>
    <verse n="5">The sounds of silence</verse>
    <verse>Four score and seven</verse>
    <sentence n="3">
        <word n="1">Hello</word>
        <word n="2">world</word>
    </sentence>
</t>

产生了想要的正确结果:

2 <div class="line">Ipsum lorem</div>
5 <span class="verse">The sounds of silence</span>
<span class="verse">Four score and seven</span>
3 <p class="sentence">
1 <span class="word">Hello</span>
2 <span class="word">world</span>
</p>

解释:正确使用模板模式