在xslt转换期间比较不同级别的属性

时间:2012-08-14 07:19:29

标签: xslt xslt-1.0

下面我创建了一个简单的XML示例,说明了我的xml是什么样的。我有一个属性,其中包含我想要观看的数字。这是一个计数器,在转换过程中我想在计数器++。

时添加一些东西

问题是我的xml文件中的级别数。在这里我只做了三个,但实际上我喜欢8或甚至更多。我需要找到一种方法来比较当前节点与前一节点(反之亦然),但需要考虑这些级别。因此,例如在下面的示例中,需要将id为4的lvl2节点与id为的lvl3节点进行比较,以便找出id属性是否已被提升

的xml:

<lvl1 id="1">
    <lvl2 id="1">
        <lvl3 id="1"></lvl3>
        <lvl3 id ="2"></lvl3>
    </lvl2>
    <lvl2 id="2">
        <lvl3 id="3"></lvl3>                        
    </lvl2>
    <lvl2 id="4"></lvl2>
</lvl1>

由于全球计数器变量是不可能的xslt我目前没有想法,似乎无法在这里或其他任何地方找到任何...

输出类似于:

  <ul>
<div>id 1</div>
<li>
  <ul>
    <li>
      <ul>
        <li></li>
        <div>id 2</div>
        <li></li>
      </ul>
    </li>
    <li>
      <ul>
        <div>id 3</div>
        <li></li>
      </ul>
    </li>
    <div>id 4</div>
    <li></li>
  </ul>
</li>

这里的样式表将xml转换为html输出但没有div:

<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
    <ul>
            <xsl:value-of select="@id"/>
            <xsl:apply-templates select="lvl1"/>
    </ul>
</xsl:template>
<xsl:template match="lvl1">
    <li class="{@id}">
        lvl 1
        <ul>
            <xsl:apply-templates select="lvl2"/>
        </ul>
    </li>
</xsl:template>
<xsl:template match="lvl2">
    <li class="{@id}">lvl 2
        <ul>
            <xsl:apply-templates select="lvl3"/>
        </ul>
    </li>
</xsl:template>
<xsl:template match="lvl3">
    <li class="{@id}">lvl 3
    </li>
</xsl:template>

2 个答案:

答案 0 :(得分:0)

如果您应用此XSLT

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" />

    <xsl:template match='/'>
        <ul>
            <xsl:apply-templates select='*' />
        </ul>
    </xsl:template>

    <xsl:template match="*">
        <li>
        <div>
            <xsl:value-of select='@id' />
            <xsl:if test='count(*)&gt;0'>
                <ul>
                    <xsl:apply-templates select='*' />
                </ul>
            </xsl:if>
        </div>
        </li>
    </xsl:template>

    </xsl:stylesheet>

你得到的东西可能就是你所要求的:

    <ul>
      <li>
        <div>1<ul>
            <li>
              <div>1<ul>
                  <li>
                    <div>1</div>
                  </li>
                  <li>
                    <div>2</div>
                  </li>
                </ul>
              </div>
            </li>
            <li>
              <div>2<ul>
                  <li>
                    <div>3</div>
                  </li>
                </ul>
              </div>
            </li>
            <li>
              <div>4</div>
            </li>
          </ul>
        </div>
      </li>
    </ul>

答案 1 :(得分:0)

问题比看起来要复杂得多,因为preceding::并不总是在这里找到当前元素之前的最后@id。您还需要检查父项@id并考虑根位置。此代码使用问题中给出的XML生成所需的结果。请参阅我的评论。

<xsl:template match="/">
    <ul>
        <xsl:apply-templates/>
    </ul>
</xsl:template>

<xsl:template match="*">
    <!-- get preceding (or parent) id -->
    <xsl:variable name="lastId">
        <xsl:choose>
            <!-- try to get id from first preceding element -->
            <xsl:when test="preceding::*[1]/@id">
                <xsl:value-of select="preceding::*[1]/@id"/>
            </xsl:when>
            <!-- there could still be ids in parent elements -->
            <xsl:when test="../@id">
                <xsl:value-of select="../@id"/>
            </xsl:when>
            <!-- or this is the root element -->
            <xsl:otherwise>
                <xsl:value-of select="0"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:variable>
    <!-- now compare current and last id -->
    <xsl:if test="@id > $lastId">
        <div>
            <xsl:text>id </xsl:text>
            <xsl:value-of select="@id"/>
        </div>
    </xsl:if>
    <!-- create list item -->
    <li>
        <!-- check for subelements -->
        <xsl:if test="*">
            <ul>
                <xsl:apply-templates/>
            </ul>
        </xsl:if>
    </li>
</xsl:template>

根据您的实际情况,您可能希望将match="*"限制为match="*[starts-with(local-name(),'lvl')]",如LarsH的评论中所建议的那样。