根据属性重新排序多个兄弟姐妹

时间:2010-12-21 21:24:16

标签: xslt

我想生成一个像这个例子的HTML文件:

  

     

Alt

     

En Lorem ipsum dolor sit amet,consectetur adipiscing elit。

     

Nunc rutrum,eros sit amet ornare faucibus。

     

的问题

     

Fr Lorem ipsum dolor坐下来,精神恍惚。

     

Nunc rutrum,eros sit amet ornare faucibus。

从以下示例XML源代码中,我无法控制:

<?xml version="1.0" encoding="ISO-8859-1"?>
<content id="">
    <header language="en">
        <enabled>true</enabled>
        <img src="http://i.stack.imgur.com/xGCNw.gif" />
        <!-- more header-related elements -->
    </header>
    <header language="fr">
        <enabled>false</enabled>
        <img src="" />
        <!-- more header-related elements -->
    </header>
    <html language="en" type="source">
    <![CDATA[
        <p>En Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
        <p>Nunc rutrum, eros sit amet ornare faucibus.</p>
        ]]>
    </html>
    <html language="fr" type="source">
    <![CDATA[
        <p>Fr Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
        <p>Nunc rutrum, eros sit amet ornare faucibus.</p>
        ]]>
    </html>
</content>

所以我写了这个XSLT来做到这一点:

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

    <xsl:template match="/">
        <h1>English</h1>
        <hr/>
        <xsl:for-each select="content/header">
            <xsl:call-template name="header">
                <xsl:with-param name="lang">en</xsl:with-param>
            </xsl:call-template>
        </xsl:for-each>
        <xsl:for-each select="content/html">
            <xsl:call-template name="html">
                <xsl:with-param name="lang">en</xsl:with-param>
            </xsl:call-template>
        </xsl:for-each>
        <hr/>
        <h1>Français</h1>
        <hr/>
        <xsl:for-each select="content/header">
            <xsl:call-template name="header">
                <xsl:with-param name="lang">fr</xsl:with-param>
            </xsl:call-template>
        </xsl:for-each>
        <xsl:for-each select="content/html">
            <xsl:call-template name="html">
                <xsl:with-param name="lang">fr</xsl:with-param>
            </xsl:call-template>
        </xsl:for-each>
    </xsl:template>

    <xsl:template name="header" match="*">
        <xsl:param name='lang'/>
        <xsl:if test="current()[@language=$lang]">
            <xsl:if test="enabled[normalize-space(text())='true']">
                <xsl:call-template name="image"/>
                <!-- more header-related elements -->
            </xsl:if>
        </xsl:if>
    </xsl:template>

    <xsl:template name="image" match="*">
        <xsl:if test="img[not(normalize-space(@src)='')]">
            <xsl:copy-of select="img"/>
        </xsl:if>
    </xsl:template>

    <xsl:template name="html" match="*">
        <xsl:param name='lang'/>
        <xsl:if test="current()[@language=$lang]">
            <xsl:value-of select="node()" disable-output-escaping="yes" />
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

也就是说,我的解决方案感觉非常冗长,但似乎能够实现有用的组合和重用度属性,这对我来说是非常重要的两件事,因为我需要转换许多结构与此示例类似的XML文档;因此,如果我的大多数XSLT都可以重用其他XSLT的部分,那么这将是非常有用的。

一些感兴趣的注释:

  • 转换速度并不重要,尽管在这方面了解更多可能会很有趣。
  • 转换将从不需要处理编码超过2种示例语言( en fr )的XML文档。

所以我想了解一下,我的解决方案对于XSLT争论者看起来是反本能的 - 甚至是错误的。

2 个答案:

答案 0 :(得分:1)

我就是这样写的:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my"
exclude-result-prefixes="my">
<xsl:output method="html" indent="yes"/>

<my:language-labels>
    <lang code="en" label="English"/>
    <lang code="fr" label="Francais"/>
</my:language-labels>

<xsl:template match="/*">
    <xsl:apply-templates select="header"/>
</xsl:template>

<xsl:template match="header">
    <xsl:variable name="curLang" select="@language"/>
    <h1>
        <xsl:value-of select="document('')/*/my:language-labels/lang[@code = $curLang]/@label"/>
    </h1>
    <hr/>
    <xsl:copy-of select="img[not(normalize-space(@src) = '')][../enabled[normalize-space() = 'true']]"/>
    <xsl:value-of select="../html[@language = $curLang]" disable-output-escaping="yes"/>
 </xsl:template>

 </xsl:stylesheet>

您的HTML示例看起来很糟糕,所以我可能有点不对劲。我的结果是:

<h1>English</h1>
<hr>
<img src="http://i.stack.imgur.com/xGCNw.gif"> 
<p>En Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Nunc rutrum, eros sit amet ornare faucibus.</p>
<h1>Francais</h1> 
<hr>
<p>Fr Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>Nunc rutrum, eros sit amet ornare faucibus.</p>

备注:

  1. 使用谓词。这是一个非常强大的工具。
  2. 如果可能,将硬编码数据保存在一个位置。
  3. apply-templates它不是一个神秘的工具,而是一个非常重要的XSLT机制。
  4. 如果您需要的参数是上下文元素,您可以在不实际传递参数的情况下调用normalize-space和其他函数。

答案 1 :(得分:1)

此转换不包含任何条件XSLT指令或任何命名模板

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

 <my:langs>
  <lang short="en">English</lang>
  <lang short="fr">Français</lang>
 </my:langs>

 <xsl:variable name="vLangs" select="document('')/*/my:langs/*"/>

 <xsl:template match="header">
  <xsl:apply-templates select="node()|@*"/>
  <hr/>
  <xsl:apply-templates select=
        "../html[@language=current()/@language]/text()"/>
 </xsl:template>

 <xsl:template match="header/@language">
  <h1><xsl:value-of select="$vLangs[@short=current()]"/></h1>
 </xsl:template>

 <xsl:template match="header[enabled='true']/img[@src and not(@src='')]">
  <xsl:copy-of select="."/>
 </xsl:template>

 <xsl:template match="html/text()">
  <xsl:value-of select="." disable-output-escaping="yes"/>
 </xsl:template>

 <xsl:template match="html|text()"/>
</xsl:stylesheet>

应用于提供的XML文档

<content id="">
    <header language="en">
        <enabled>true</enabled>
        <img src="http://i.stack.imgur.com/xGCNw.gif" />
        <!-- more header-related elements -->
    </header>
    <header language="fr">
        <enabled>false</enabled>
        <img src="" />
        <!-- more header-related elements -->
    </header>
    <html language="en" type="source">
    <![CDATA[
             <p>En Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
             <p>Nunc rutrum, eros sit amet ornare faucibus.</p>
             ]]>
   </html>
    <html language="fr" type="source">
    <![CDATA[
            <p>Fr Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
            <p>Nunc rutrum, eros sit amet ornare faucibus.</p>
            ]]>
 </html>
</content>

产生了想要的正确结果

<h1>English</h1>
<img src="http://i.stack.imgur.com/xGCNw.gif" />
<hr />

             <p>En Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
             <p>Nunc rutrum, eros sit amet ornare faucibus.</p>

   <h1>Français</h1>
<hr />

            <p>Fr Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
            <p>Nunc rutrum, eros sit amet ornare faucibus.</p>

请注意

  1. 使用模板和模式匹配

  2. 使用 <xsl:apply-templates>

  3. 在模板的匹配模式中使用谓词,并在<xsl:apply-templates>

    中选择必要的节点列表