使用XSL合并和排序多个XML文件

7

问题是使用XSL合并和排序多个XML文件,并输出有效的HTML,可在Firefox >= 3.5以及可能的情况下在IE >= 7上查看。答案应尽可能简单(性能不重要)。

文件a.xml

<?xml version="1.0"?>
<root>
    <tag>cc</tag>
    <tag>aa</tag>
</root>

文件 b.xml

<?xml version="1.0"?>
<root>
    <tag>xx</tag>
    <tag>bb</tag>
</root>

文件 index.xml

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="merge.xslt"?>
<list>
    <entry>a.xml</entry>
    <entry>b.xml</entry>
</list>

文件合并.xslt

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ph="http://ananas.org/2003/tips/photo">

    <xsl:output method="html"/>

    <xsl:template match="list">
        <html>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="entry">
        <xsl:for-each select="document(.)/root/tag">
            <!-- This will only sort the values of a single file -->
            <xsl:sort select="." data-type="text" order="ascending" />
            - <xsl:value-of select="."/> <br/>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

当前输出:

  • aa

  • cc

  • bb

  • xx

期望的输出:

  • aa

  • bb

  • cc

  • xx


1
好问题,+1。请看我的答案,其中包含一个完整、非常简短和易于实现的解决方案,不涉及任何其他答案中的复杂性:没有扩展函数,没有变量,没有 xsl:for-each... - Dimitre Novatchev
还添加了详尽的解释。 - Dimitre Novatchev
1个回答

9
这个问题的解决方法非常简单,只需要进行一个非常短的转换即可(绝对不需要使用扩展函数!):
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/*">
  <html>
   <ul>
    <xsl:apply-templates
       select="document(entry)/*/tag">
      <xsl:sort/>
    </xsl:apply-templates>
   </ul>
  </html>
 </xsl:template>

 <xsl:template match="tag">
  <li><xsl:value-of select="."/></li>
 </xsl:template>
</xsl:stylesheet>

当应用此转换于提供的index.xml文件时:
<list>
    <entry>a.xml</entry>
    <entry>b.xml</entry>
</list>

期望的,正确的结果已经生成:

<html>
   <ul>
      <li>aa</li>
      <li>bb</li>
      <li>cc</li>
      <li>xx</li>
   </ul>
</html>

并且在任何浏览器中都会呈现为:

  • aa
  • bb
  • cc
  • xx

解释: 该解决方案利用了标准的XSLT函数document()的强大功能。 正如W3C XSLT 1.0推荐的定义所述:

当文档函数恰好具有一个参数,并且参数是一个节点集,则对于参数节点集中的每个节点,将使用调用文档函数的结果作为第一个参数的字符串值的并集

这解释了我们代码片段的效果:

<xsl:apply-templates
   select="document(entry)/*/tag">
  <xsl:sort/>
</xsl:apply-templates>

这里发生的事情是,document()函数的参数是index.xml顶层元素下所有entry子元素的节点集合。结果是所有文档节点的并集。

因此:

select="document(entry)/*/tag"

选取在index.xml中引用的所有文档中的所有tag元素。然后通过进行排序,并且已排序的节点列表中的每个元素都会被与tag匹配的模板处理。


已接受,因为答案可行且易于理解。非常好的解释! - gaddomn
2
我不知道为什么我把事情搞得这么复杂。我需要休息一下。最好的和简单的方法加1分。 - Emiliano Poggi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接