使用xslt对xml文件元素进行排序

时间:2013-03-10 15:17:22

标签: xml xslt

我有以下xml文件:

<WindowProperties>
<skin>LP Connect</skin>
<showToOperator>false</showToOperator>
<showToVisitor>false</showToVisitor>
<ChatWindow>
  <field>
    <key>direction</key>
    <val>ltr</val>
  </field>
  <field>
    <key>enableCustomizedHeaderImageUrl</key>
    <val>false</val>
  </field>
  <field>
    <key>brandType</key>
    <val>noImage</val>
  </field>
  <field>
    <key>brandHeight</key>
    <val>158</val>
  </field>      
</ChatWindow>

我想使用关键元素在聊天窗口中对字段进行排序,因此xml将如下所示:

<WindowProperties>
    <skin>LP Connect</skin>
    <showToOperator>false</showToOperator>
    <showToVisitor>false</showToVisitor>
    <ChatWindow>
    <field>
        <key>brandHeight</key>
        <val>158</val>
      </field> 
<field>
        <key>brandType</key>
        <val>noImage</val>
      </field>

      <field>
        <key>direction</key>
        <val>ltr</val>
      </field>
      <field>
        <key>enableCustomizedHeaderImageUrl</key>
        <val>false</val>
      </field>

    </ChatWindow>
 </WindowProperties>

我尝试了以下xsl:

<ChatWindow>

                    <xsl:template match="ChatWindow">
                        <xsl:for-each select="field">
                            <xsl:sort select="key"/>
                            <key><xsl:value-of select="key"/></key>
                            <value><xsl:value-of select="val"/></value>
                        </xsl:for-each>
                    </xsl:template>

                </ChatWindow>

但这不起作用。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:3)

这个简单的XSLT应该可以胜任:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
  <xsl:strip-space elements="*" />

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="ChatWindow">
    <xsl:copy>
      <xsl:apply-templates select="field">
        <xsl:sort select="key" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

在样本输入上运行时,会产生:

<WindowProperties>
  <skin>LP Connect</skin>
  <showToOperator>false</showToOperator>
  <showToVisitor>false</showToVisitor>
  <ChatWindow>
    <field>
      <key>brandHeight</key>
      <val>158</val>
    </field>
    <field>
      <key>brandType</key>
      <val>noImage</val>
    </field>
    <field>
      <key>direction</key>
      <val>ltr</val>
    </field>
    <field>
      <key>enableCustomizedHeaderImageUrl</key>
      <val>false</val>
    </field>
  </ChatWindow>
</WindowProperties>

如果您出于某种原因绝对必须使用<xsl:output method="text" />,则可以执行以下操作,但我不建议这样做:

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

  <xsl:template match="*">
    <xsl:value-of select="concat('&lt;', name(), '&gt;')"/>
    <xsl:apply-templates />
    <xsl:value-of select="concat('&lt;/', name(), '&gt;')"/>
  </xsl:template>

  <xsl:template match="ChatWindow">
    <xsl:value-of select="concat('&lt;', name(), '&gt;')"/>
    <xsl:apply-templates select="field">
      <xsl:sort select="key" />
    </xsl:apply-templates>
    <xsl:value-of select="concat('&lt;/', name(), '&gt;')"/>
  </xsl:template>
</xsl:stylesheet>

或者更长一点,但更清洁一点:

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

  <xsl:template name="tag">
    <xsl:param name="slash" />
    <xsl:value-of select="concat('&lt;', $slash, name(), '&gt;')"/>
  </xsl:template>

  <xsl:template name="cTag">
    <xsl:call-template name="tag">
      <xsl:with-param name="slash" select="'/'" />
    </xsl:call-template>
  </xsl:template>

  <xsl:template match="*">
    <xsl:call-template name="tag" />
    <xsl:apply-templates />
    <xsl:call-template name="cTag" />
  </xsl:template>

  <xsl:template match="ChatWindow">
    <xsl:call-template name="tag" />
    <xsl:apply-templates select="field">
      <xsl:sort select="key" />
    </xsl:apply-templates>
    <xsl:call-template name="cTag" />
  </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:1)

编辑:请参阅@JLRishe的回答,因为这是正确的方法。我在下面的回答满足'文本'输出要求,但实际上更复杂并完成同样的事情。

我已经删除了我的完整示例,并保留了我原始答案中的<CDATA>代码,以防万一有人需要在XSLT的文本输出中生成XML元素或其他标记(比如说)用于生成评论或某事)。如果您希望生成纯XML,这不是最好的方法:

原始答案:

回顾一下,我理解这个问题,你有一个返回“text”(不是XML)的XSLT模板,但你希望在输出中保留XML标签,使它看起来像一样。

为此,您需要围绕要作为文本处理的XML标记的<CDATA[ ]]>部分,如下所示:

    <xsl:template match="ChatWindow">
      <xsl:for-each select="field">
        <xsl:sort select="key"/>
        <![CDATA[<key>]]>
          <xsl:value-of select="key"/>
        <![CDATA[</key>]]>
        <![CDATA[<value>]]> 
          <xsl:value-of select="val"/>
        <![CDATA[</value>]]>
      </xsl:for-each>
    </xsl:template>

注意你也可以在中间结合CDATA部分,但我认为上面看起来更干净。 (结果相同)

    <xsl:template match="ChatWindow">
      <xsl:for-each select="field">
        <xsl:sort select="key"/>
        <![CDATA[<key>]]>
          <xsl:value-of select="key"/>
        <![CDATA[</key>
        <value>]]>
          <xsl:value-of select="val"/>
        <![CDATA[</value>]]>
      </xsl:for-each>
    </xsl:template>