在XSLT中组合空格分隔的属性

时间:2017-03-17 17:33:08

标签: xslt

我正在处理的转换合并了两个具有空格分隔属性的模板。

一个例子是:

<document template_id="1">
  <header class="class1 class2" />
</document>
<document template_id="2">
  <header class="class3 class4" />
</document>

转换后我希望它像这样:

<document>
  <header class="class1 class2 class3 class4" />
</document>

如何实现这一目标?

我尝试过(从记忆中写作):

<xsl:template match="/">
  <header>
    <xsl:attribute name="class">
      <xsl:for-each select=".//header">
        <xsl:value-of select="@class"/>
      </xsl:for-each>
    </xsl:attribute>
  </header>
</xsl:template>

但是,它们将它们全部加在一起,但是我需要将它们分开......如果没有它也会很棒。

谢谢

2 个答案:

答案 0 :(得分:1)

尝试此模板,除了第一个

之外,它只是在所有标题之前添加一个空格
<xsl:template match="/">
  <header>
    <xsl:attribute name="class">
      <xsl:for-each select=".//header">
        <xsl:if test="position() > 1">
            <xsl:text> </xsl:text>
        </xsl:if>
        <xsl:value-of select="@class"/>
      </xsl:for-each>
    </xsl:attribute>
  </header>
</xsl:template>

答案 1 :(得分:0)

如果您希望您的课程不重复,请使用以下XSLT:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exsl="http://exslt.org/common"
  extension-element-prefixes="exsl">
  <xsl:output method="xml" encoding="UTF-8" indent="yes" />

  <xsl:template match="/">
    <document>
      <xsl:variable name="cls1">
        <xsl:for-each select=".//header/@class">
          <xsl:call-template name="tokenize">
            <xsl:with-param name="txt" select="."/>
          </xsl:call-template>  
        </xsl:for-each>
      </xsl:variable>
      <xsl:variable name="cls" select="exsl:node-set($cls1)"/>
      <header>
        <xsl:attribute name="class">
          <xsl:for-each select="$cls/*[not(preceding-sibling::* = .)]">
            <xsl:value-of select="."/>
            <xsl:if test="position() &lt; last()">
              <xsl:text> </xsl:text>
            </xsl:if>
          </xsl:for-each>
        </xsl:attribute>
      </header>
    </document>
  </xsl:template>

  <xsl:template name="tokenize">
    <xsl:param name="txt"/>
    <xsl:if test="$txt">
      <xsl:if test="contains($txt, ' ')">
        <cls>
          <xsl:value-of select="substring-before($txt, ' ')"/>
        </cls>
        <xsl:call-template name="tokenize">
          <xsl:with-param name="txt" select="substring-after($txt, ' ')"/>
        </xsl:call-template>
      </xsl:if>
      <xsl:if test="not(contains($txt, ' '))">
        <cls>
          <xsl:value-of select="$txt"/>
        </cls>
      </xsl:if>
    </xsl:if>
  </xsl:template>
</xsl:transform>

XSLT 1.0 中,它比 XSLT 2.0 困难得多,但如您所见, 这是可能的。

修改

使用 Muenchian分组的修订版本(灵感来自Michael的评论):

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exsl="http://exslt.org/common"
  extension-element-prefixes="exsl">
  <xsl:output method="xml" encoding="UTF-8" indent="yes" />

  <xsl:variable name="cls1">
    <xsl:for-each select=".//header/@class">
      <xsl:call-template name="tokenize">
        <xsl:with-param name="txt" select="."/>
      </xsl:call-template>
    </xsl:for-each>
  </xsl:variable>
  <xsl:variable name="cls2" select="exsl:node-set($cls1)"/>
  <xsl:key name="classKey" match="cls" use="."/>

  <xsl:template match="/">
    <document>
      <header>
        <xsl:attribute name="class">
          <xsl:for-each select="$cls2/*[generate-id() = generate-id(key('classKey', .)[1])]">
            <xsl:value-of select="."/>
            <xsl:if test="position() &lt; last()">
              <xsl:text> </xsl:text>
            </xsl:if>
          </xsl:for-each>
        </xsl:attribute>
      </header>
    </document>
  </xsl:template>

  <xsl:template name="tokenize">
    <xsl:param name="txt"/>
    <xsl:if test="$txt">
      <xsl:if test="contains($txt, ' ')">
        <cls>
          <xsl:value-of select="substring-before($txt, ' ')"/>
        </cls>
        <xsl:call-template name="tokenize">
          <xsl:with-param name="txt" select="substring-after($txt, ' ')"/>
        </xsl:call-template>
      </xsl:if>
      <xsl:if test="not(contains($txt, ' '))">
        <cls>
          <xsl:value-of select="$txt"/>
        </cls>
      </xsl:if>
    </xsl:if>
  </xsl:template>
</xsl:transform>