如何在XSLT中包含兄弟姐妹?

时间:2014-01-24 15:44:04

标签: xml xslt xslt-1.0

我有xml,所以我无法改变

<entry>
    <sn>1 a</sn>
    <dt>:to run away often from danger or evil</dt>
    <sn>b</sn>
    <dt>:to hurry toward a place of security</dt>
    <sn>2</sn>
    <dt>:to pass away swiftly</dt>
</entry>

我正在尝试编写xslt以使其看起来像这样

    <div class="entry">
        <div class="def_group">
            <span class="def_group_number">1</span>
            <div class="def_value">
                 <span class="def_value_letter">a</span>
                 <span class="the_def">:to run away often from danger or evil</span>
            </div>

            <div class="def_value">
                 <span class="def_value_letter">b</span>
                 <span class="the_def">:to hurry toward a place of security</span>
            </div>
        </div>

        <div class="def_group">
            <span class="def_group_number">2</span>
            <div class="def_value">
                 <span class="the_def">:to pass away swiftly</span>
            </div>
        </div>
   </div>

当我把它分解时,我真的有两个问题。

如何使用XSLT 1.0将三个&lt; sn&gt; (“字母”,“数字”,“数字字母”)?

并且,在包含数字的情况下,如何使用&lt; div>将包含其兄弟&lt; dt&gt;小时候?

1 个答案:

答案 0 :(得分:1)

XSLT 1.0不适合字符串操作,但我认为可以做到这一点。首先,我们需要找到属于第一个的所有字母sn,所以让我们为它定义一个键

<xsl:key name="subsenseByMainSense"
   match="sn[not(number(substring(., 1, 1)) = number(substring(., 1, 1)))]"
   use="generate-id(preceding-sibling::sn[
           number(substring(., 1, 1)) = number(substring(., 1, 1))][1])" />

这看起来很奇怪,但它都是成语 - number() = number()是一种检查有问题的东西(这里是节点的字符串值的第一个字符)是否为数字的方法。如果你正在检查的东西是一个数字,那么测试就是检查一个数字是否与自身相等,这总是正确的;如果一个数字,则测试为NaN = NaN,这总是假的。

现在从entry开始,您希望每个def_groupsn开头,以数字开头:

<xsl:template match="entry">
  <div class="entry">
    <xsl:apply-templates select="sn[number(substring(., 1, 1))
                                  = number(substring(., 1, 1))]" />
  </div>
</xsl:template>

<xsl:template match="sn">
  <div class="def_group">
    <span class="def_group_number">
      <xsl:choose>
        <xsl:when test="contains(., ' ')">
          <xsl:value-of select="substring-before(., ' ')"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="." />
        </xsl:otherwise>
      </xsl:choose>
    </span>

    <!-- do the value(s) of this element and any following letter-only ones -->
    <xsl:apply-templates mode="value"
         select=". | key('subsenseByMainSense', generate-id())" />
  </div>
</xsl:template>

现在对于值位,如果此元素有一个字母,则添加def_value_letter,否则只添加the_def

<xsl:template match="sn" mode="value">
  <xsl:variable name="letter"
     select="translate(., translate(., 'abcdefghijklmnopqrstuvwxyz', ''), '')" />
  <div class="def_value">
    <xsl:if test="$letter">
      <span class="def_value_letter">
        <xsl:value-of select="$letter" />
      </span>
    </xsl:if>
    <span class="the_def">
      <xsl:value-of select="following-sibling::dt[1]" />
    </span>
  </div>
</xsl:template>

双翻译是另一种习惯用法 - 它是一种从字符串中删除所有字符的方法,除了特定“白名单”中的那些字符,因此在这种情况下要删除所有非字母字符字符串。