如果存在特定属性,则使用XSLT为每个节点创建单独的父级

时间:2016-07-01 07:45:17

标签: xml xslt

我想将<text>包含在具有@align属性的单独<p>中。有关更多说明,请参阅以下示例。

来源

<p>
 <text>Check</text>
 <text>Check2</text>
 <text align="center">Final</text>
 <text align="right">Final Check</text>
</p>

XSLT代码:

<xsl:template match="p">
    <xsl:choose>
        <xsl:when test="child::text/@align">
            <xsl:element name="p">
                <xsl:attribute name="align">
                    <xsl:value-of select="child::text/@align"/>
                </xsl:attribute>
                <xsl:apply-templates/>
            </xsl:element>
        </xsl:when>
    </xsl:choose>
</xsl:template>

我的输出

<p align="center right">
  <text>Check</text>
  <text>Check2</text>
  <text>Final</text>
  <text>Final Check</text>
</p>

预期产出

<p>
  <text>Check</text>
  <text>Check2</text>
</p>
<p align="center">
  <text>Final</text>
</p>
<p align="right">
  <text>Final Check</text>
</p>

3 个答案:

答案 0 :(得分:1)

在使用XSLT 2.0时,您可以使用xsl:for-each-grouptext元素与align属性组合在一起,将那些元素组合在一起,并在每种情况下采取相应的操作

试试这个XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml" indent="yes" />
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="p">
    <xsl:for-each-group select="text" group-adjacent="boolean(@align)">
      <xsl:choose>
        <xsl:when test="current-grouping-key()">
          <xsl:for-each select="current-group()">
             <p align="{./@align}">
                <xsl:apply-templates select="." />
             </p>
          </xsl:for-each>
        </xsl:when>
        <xsl:otherwise>
          <p>
            <xsl:apply-templates select="current-group()" />
          </p>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each-group>
  </xsl:template>

  <xsl:template match="text/@align" />
</xsl:stylesheet>

答案 1 :(得分:0)

这是一个简单的解决方案。

  <xsl:template match="p">
    <xsl:apply-templates/>
  </xsl:template>
  <xsl:template match="text[@align='center']">
    <xsl:element name="p">
      <xsl:attribute name="align">
        <xsl:value-of select="'center'"/>
      </xsl:attribute>
      <xsl:element name="text">
        <xsl:value-of select="."/>
      </xsl:element>
    </xsl:element>
  </xsl:template>
  <xsl:template match="text[@align='right']">
    <xsl:element name="p">
      <xsl:attribute name="align">
        <xsl:value-of select="'right'"/>
      </xsl:attribute>
      <xsl:element name="text">
        <xsl:value-of select="."/>
      </xsl:element>
    </xsl:element>
  </xsl:template>  
  <xsl:template match="text">
    <xsl:element name="p">
      <xsl:element name="text">
        <xsl:value-of select="."/>
      </xsl:element>
    </xsl:element>
  </xsl:template>

答案 2 :(得分:0)

我建议你这样做:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="p">
    <xsl:for-each-group select="text" group-adjacent="string(@align)">
         <p>
            <xsl:if test="current-grouping-key()">
                <xsl:attribute name="align" select="current-grouping-key()" />
            </xsl:if>
            <xsl:apply-templates select="current-group()" />
        </p>
    </xsl:for-each-group>
</xsl:template>

<xsl:template match="text/@align"/>

</xsl:stylesheet>

要了解此建议与其他建议之间的区别,请将此作为测试输入:

<p>
    <text>Check</text>
    <text>Check2</text>
    <text align="center">Check3</text>
    <text align="center">Check4</text>
    <text align="right">Check5</text>
    <text>Check6</text>
</p>