具有附加标题行复制和操作的XSLT标识转换

时间:2018-04-25 21:08:39

标签: xml xslt

我一直在努力解决这个问题,我希望你能提供帮助。我自己尝试了很多方法,并搜索了这个网站和其他人,但找不到合适的答案。非常感谢提前。

我想获取输入XML文档并输出具有这些更改的类似副本:

  1. 每次兄弟姐妹的某个元素的值发生变化时插入的同级格式的新标题记录。 header元素将是第一个兄弟的副本,稍有变化。
  2. 所有常规的非标头记录也会更改一些值。
  3. 我尝试使用http://exslt.org/common节点集函数以及节点集作为xslt 2.0中的变量但是丢失了。

    示例输入,假定行按类型排序。

    <fruits>
        <fruit>
    
            <row>1</row>
            <type> Apple </type>
            <name> Gala </name>
            <color> Red </color>
            <country> US </country>
        </fruit>
    
        <fruit>
    
            <row>2</row>
            <type> Apple </type>
            <name> Fuji </name>
            <color> Red </color>
            <country> US </country>
        </fruit>
    
        <fruit>
    
            <row>3</row>
            <type> Apple </type>
            <name> Golden Delcious </name>
            <color> Yellow </color>
            <country> US </country>
        </fruit>
        <fruit>
    
            <row>4</row>
            <type> Orange </type>
            <name> Clementine </name>
            <color> Orange </color>
            <country> US </country>
        </fruit>
        <fruit>
            <row>5</row>
            <type> Orange </type>
            <name> Sunburst </name>
            <color> Orange </color>
            <country> US </country>
        </fruit>
    </fruits>
    

    这是示例输出。对于按类型划分的每组行,请以相同格式在该类型行上方添加标题行。名称和颜色应该在标题行中排除,行值应该有一个&#39; H&#39;前置它,否则它与下一个常规行相同。在以下相同类型的常规行中,应该将该国家排除在外。

    <fruits>
        <fruit>
    
            <row>H1</row>
            <type> Apple </type>
            <name> </name>
            <color> </color>
            <country> US </country>
        </fruit>
        <fruit>
    
            <row>1</row>
            <type> Apple </type>
            <name> Gala </name>
            <color> Red </color>
            <country> </country>
        </fruit>
    
        <fruit>
    
            <row>2</row>
            <type> Apple </type>
            <name> Fuji </name>
            <color> Red </color>
            <country> </country>
        </fruit>
    
        <fruit>
    
            <row>3</row>
            <type> Apple </type>
            <name> Golden Delcious </name>
            <color> Yellow </color>
            <country> </country>
        </fruit>
        <fruit>
    
            <row>H4</row>
            <type> Orange </type>
            <name> </name>
            <color> </color>
            <country> US </country>
        </fruit>
        <fruit>
    
            <row>4</row>
            <type> Orange </type>
            <name> Clementine </name>
            <color> Orange </color>
            <country> </country>
        </fruit>
        <fruit>
            <row>5</row>
            <type> Orange </type>
            <name> Sunburst </name>
            <color> Orange </color>
            <country> </country>
        </fruit>
    </fruits>
    

    这是我尝试过的XSLT的一部分。我首先进行了身份转换,并且每次类型更改时都成功创建了一个额外的标题行。但是,我不知道如何操纵标题或常规行来获得所需的输出。

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" indent="yes"/>
    
        <!-- identity transform -->
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
        <!-- create the extra header row every time the type changes -->
        <xsl:template match="fruit">
            <xsl:choose>
                <xsl:when test="type != preceding-sibling::*[1]/type">
                    <xsl:copy>
                        <xsl:apply-templates select="node() | @*"/>
                    </xsl:copy>
                </xsl:when>
                <!-- create the header row for the first row where preceding sibling is null -->
                <xsl:when test="row = 1">
                    <xsl:copy>
                        <xsl:apply-templates select="node() | @*"/>
                    </xsl:copy>
                </xsl:when>
                <xsl:otherwise>
                </xsl:otherwise>
            </xsl:choose>
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
    
    
    </xsl:stylesheet>
    

    xslt 1.0中的解决方案将是首选,但2.0也可以。

    非常感谢你!

4 个答案:

答案 0 :(得分:1)

我会相应地编辑答案,但是,你的意思是这样吗?

(这里我只改变&#34;行&#34;节点为例)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>

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

    <!-- create the extra header row every time the type changes -->
    <xsl:template match="fruit">
        <xsl:choose>
            <xsl:when test="type != preceding-sibling::*[1]/type">
                <xsl:copy>
                    <xsl:apply-templates select="node() | @*"/>
                </xsl:copy>
            </xsl:when>
            <!-- create the header row for the first row where preceding sibling is null -->
            <xsl:when test="row = 1">
                <xsl:copy>
                    <xsl:apply-templates select="node() | @*"/>
                </xsl:copy>
            </xsl:when>
            <xsl:otherwise>
            </xsl:otherwise>
        </xsl:choose>
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:0)

在XSLT 2.0中,这是

<xsl:template match="fruits">
  <fruits>
    <xsl:for-each-group select="fruit" group-adjacent="type">
      <xsl:copy>
        <row>H<xsl:value-of select="row"/></row>
        <type><xsl:value-of select="type"/></type>
        <name/>
        <color/>
        <country><xsl:value-of select="country"/></country>
      </xsl:copy>
      <xsl:copy-of select="current-group()"/>
    </xsl:for-each-group>
  </fruits>
</xsl:template>

答案 2 :(得分:0)

我会相应地修改答案 -

XSLT脚本代码:              

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

    <xsl:template match="fruit">
        <xsl:variable name="type" select="child::type"/>
        <xsl:choose>
            <xsl:when test="preceding-sibling::*[1][type != $type] or (count(preceding-sibling::fruit) = 0)">
                <fruit>
                    <row>
                        <xsl:value-of select="concat('H', row)"/>
                    </row>
                    <type> <xsl:value-of select="type"/></type>
                    <name> </name>
                    <color> </color>
                    <country> <xsl:value-of select="country"/> </country>
                </fruit>
                <xsl:copy>
                    <xsl:apply-templates select="@*|node()"/>
                </xsl:copy>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy>
                    <xsl:apply-templates select="@*|node()"/>
                </xsl:copy>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

XSLT脚本生成的输出:

<?xml version="1.0" encoding="UTF-8"?>
<fruits>
    <fruit>
      <row>H1</row>
      <type> Apple </type>
      <name/>
      <color/>
      <country> US </country>
   </fruit>
   <fruit>

        <row>1</row>
        <type> Apple </type>
        <name> Gala </name>
        <color> Red </color>
        <country> US </country>
    </fruit>

    <fruit>

        <row>2</row>
        <type> Apple </type>
        <name> Fuji </name>
        <color> Red </color>
        <country> US </country>
    </fruit>

    <fruit>

        <row>3</row>
        <type> Apple </type>
        <name> Golden Delcious </name>
        <color> Yellow </color>
        <country> US </country>
    </fruit>
    <fruit>
      <row>H4</row>
      <type> Orange </type>
      <name/>
      <color/>
      <country> US </country>
   </fruit>
   <fruit>

        <row>4</row>
        <type> Orange </type>
        <name> Clementine </name>
        <color> Orange </color>
        <country> US </country>
    </fruit>
    <fruit>
        <row>5</row>
        <type> Orange </type>
        <name> Sunburst </name>
        <color> Orange </color>
        <country> US </country>
    </fruit>
</fruits>

答案 3 :(得分:0)

以下是在XSLT 2.0版中处理问题的另一种方法:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>

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

    <xsl:template match="fruits">
        <fruits>
            <xsl:for-each-group select="fruit" group-by="type">
                <fruit>
                    <row>
                        <xsl:value-of select="concat('H', current-group()[1]//row)"></xsl:value-of>
                    </row>
                    <type> <xsl:value-of select="current-group()[1]//type"/></type>
                    <name> </name>
                    <color> </color>
                    <country> <xsl:value-of select="current-group()[1]//country"/> </country>
                </fruit>
                <xsl:copy-of select="current-group()"/>                
            </xsl:for-each-group>
       </fruits>
    </xsl:template>   
</xsl:stylesheet>