CSDN上无意中看到了这样一篇老帖 ,关于XSLT转换的。
XSLT原文:
<?xml   version="1.0"   encoding="GB2312"?>  
  <?xml-stylesheet   type="text/xsl"   href="sort.xsl"?>  
  <root>  
  <item   f1="
浙江"   f2="绍兴"   f3="aaa"/>  
  <item   f1="
江苏"   f2="苏州"   f3="bbb"/>  
  <item   f1="
浙江"   f2="杭州"   f3="ccc"/>  
  <item   f1="
山东"   f2="济南"   f3="ddd"/>  
  <item   f1="
山东"   f2="青岛"   f3="eee"/>  
  <item   f1="
江苏"   f2="南京"   f3="fff"/>  
  <item   f1="
山东"   f2="青岛"   f3="ggg"/>  
  <item   f1="
江苏"   f2="南京"   f3="hhh"/>  
  <item   f1="
山东"   f2="济南"   f3="iii"/>  
  </root>  
要转换的结果文件:
江苏-   南京:fffhhh   苏州:bbb  
山东-   济南:dddiii   青岛:eeeggg  
浙江-   杭州:ccc   绍兴:aaa  
意思是要把在同一个省同一个市的归纳在一起,并且省市都要按字典排序。
楼主想到了一点:轴是用在原文档中的。
其实,这个问题可以解决:
首先第一步:提取f1
代码:
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
   <xsl:apply-templates select="root/item">
      <xsl:sort select="@f1"/> 
   </xsl:apply-templates>
</xsl:template>
<xsl:template match="item">
   <xsl:if test="not(preceding-sibling::*[@f1=current()/@f1])">
      <xsl:value-of select="concat(@f1,'-')"/>
      <br/>
   </xsl:if>
</xsl:template>
</xsl:stylesheet>
OK,可以得到下面的结果:
江苏-
山东
-
浙江-
现在需要输出第二项内容:即f2,可是该如何实现呢?我们知道apply-templates,通常只应用于子孙节点的模板。第一步我们已经到了item了,下面就是属性了,应用属性的模板,该如何实现属性的唯一性输出呢?
其实打破常理来想,我们可以再次应用item的模板,但是如何应用呢?我们应该先利用for-each将当前节点移到item的顶层,那么就可以再次应用item的模板了,但是,另一个问题又出来了,再次应用这个模板,是不是会混乱了,我们这次的目的是输出f2啊,OK,还记得吗?<xsl:templates>有一个mode属性。代码也就顺理成章的出来了(当然还得保证所选定的item节点没变):
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
   <xsl:apply-templates select="root/item" mode="a" >
      <xsl:sort select="@f1"/> 
   </xsl:apply-templates>
</xsl:template>
<xsl:template match="item" mode="a">
   <xsl:if test="not(preceding-sibling::*[@f1=current()/@f1])">
      <xsl:value-of select="concat(@f1,'-')"/>
      <xsl:variable name="f1" select="@f1"/>
      <xsl:for-each select="..">
         <xsl:apply-templates select="item[@f1 = $f1]" mode="b">
            <xsl:sort select="@f2"/>
         </xsl:apply-templates>
      </xsl:for-each>
      <br/>
   </xsl:if>
</xsl:template>
<xsl:template match="item" mode="b">
   <xsl:if test="not(preceding-sibling::*[@f2=current()/@f2])">
      <xsl:value-of select="concat(' ',@f2,':')"/>
   </xsl:if>
</xsl:template>
</xsl:stylesheet>