0

我有以下 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>

我想使用 key 元素对聊天窗口中的字段进行排序,因此 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>

但这没有用。任何帮助表示赞赏。

4

2 回答 2

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>
于 2013-03-10T17:32:01.420 回答
1

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

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

原答案:

回顾一下,以便我理解这个问题,您有一个返回“文本”(不是 XML)的 XSLT 模板,但您希望在输出中保留 XML 标记,使其看起来像 XML。

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

    <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>
于 2013-03-10T15:43:43.593 回答