首页 > 解决方案 > 使用 xslt 将 xml 转换为 html 列表

问题描述

我有一个将 xml 文件转换为 html 列表的 xslt 代码。输入输出样本如下:

输入:

<Beverages>
    <Water/>
    <Coffee/>
    <Tea>
      <BlackTea/>
      <WhiteTea id="cti" value="ctv" >Camomile Tea</WhiteTea>
      <GreenTea id="gti" value="gtv">
        <Sencha/>
        <Gyokuro/>
        <Matcha/>
        <PiLoChun/>
      </GreenTea>
    </Tea>
  </Beverages>

和输出:

<ul>
      <li>
          <span class="caret">&lt;Beverages&gt;</span>
          <ul class="nested">
              <li><span>&lt;Water/&gt;</span></li>
              <li><span>&lt;Coffee/&gt;</span></li>
              <li>
                  <span class="caret">&lt;Tea&gt;</span>
                  <ul class="nested">
                      <li><span>&lt;BlackTea/&gt;</span></li>
                      <li><span>&lt;WhiteTea id="cti" value="ctv"&gt;</span>Camomile Tea<span>&lt;/WhiteTea&gt;</span></li>
                      <li>
                          <span>&lt;GreenTea id="gti" value="gtv"&gt;</span>
                          <ul class="nested">
                              <li><span>&lt;Sencha/&gt;</span></li>
                              <li><span>&lt;Gyokuro/&gt;</span></li>
                              <li><span>&lt;Matcha/&gt;</span></li>
                              <li><span>&lt;PiLoChun/&gt;</span></li>
                          </ul>
                          <span>&lt;/GreenTea&gt;</span>
                      </li>
                  </ul>
              </li>
          </ul>
          <span>&lt;/Beverages&gt;</span>
      </li>
  </ul>

这是我的 xslt,但它与我想要的不完全相同:


  <xsl:template match="/">
    <ul><xsl:apply-templates/></ul>
  </xsl:template>
  <xsl:template match="*">
    <li> <span class="caret"><xsl:value-of select="concat('&lt;',name())" />
        <xsl:for-each select="@*">
          <xsl:value-of select="concat(' ',name())"/>=<xsl:value-of select="concat('&quot;',.,'&quot;')" />  
        </xsl:for-each>&gt;</span>
      <xsl:if test="text()">
        <xsl:apply-templates select="text()" />
      </xsl:if>
      <xsl:if test="*">
        <ul class="nested"><xsl:apply-templates/></ul>
      </xsl:if>
      <span><xsl:value-of select="concat('&lt;','/' ,name() , '&gt;')" /></span></li>
  </xsl:template>

问题是这段代码无法区分父元素和非父元素。对于父元素,我们需要添加 class="caret" 属性,但对于非父元素,我们不应该添加此类。

标签: xslt

解决方案


这应该适合你。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <ul>
            <xsl:apply-templates/>
        </ul>
    </xsl:template>
    <xsl:template match="*">
        <li>
            <span>
                <xsl:if test="*">
                    <xsl:attribute name="class">
                        <xsl:value-of select="'caret'"/>
                    </xsl:attribute>
                </xsl:if>
                <xsl:value-of select="concat('&lt;',name())"/>
                <xsl:for-each select="@*">
                    <xsl:value-of select="concat(' ', name(), '=', '&quot;', ., '&quot;')"/>
                </xsl:for-each>
                <xsl:choose>
                    <xsl:when test="text() or *">
                        <xsl:value-of select="'&gt;'"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="'\&gt;'"/>
                    </xsl:otherwise>
                </xsl:choose>
            </span>
            <xsl:if test="text()">
                <xsl:value-of select="text()"/>
            </xsl:if>
            <xsl:if test="*">
                <ul class="nested">
                    <xsl:apply-templates/>
                </ul>
            </xsl:if>
            <xsl:if test="text() or *">
                <span>
                    <xsl:value-of select="concat('&lt;','/' ,name() , '&gt;')"/>
                </span>
            </xsl:if>
        </li>
    </xsl:template>
</xsl:stylesheet>

推荐阅读