对连续节点

时间:2016-09-26 08:47:44

标签: sorting xslt xslt-1.0

我有一个大致相似的XML文件(实际文件要复杂得多,在这个例子中一切都被截断了):

<?xml version="1.0" encoding="utf-8"?>
<root>
    <element>
        <tag1>1</tag1>
        <tag2>stuff</tag2>
        <type>String</type>
        <tag3>stuff</tag3>
    </element>
    <element>
        <tag1>2</tag1>
        <tag2>stuff</tag2>
        <type>String</type>
        <type>Date</type>
        <type>Float</type>
        <tag3>stuff</tag3>
    </element>
    <element>
        <tag1>3</tag1>
        <tag2>stuff</tag2>
        <type>DateTime</type>
        <tag3>stuff</tag3>
    </element>
    <element>
        <tag1>4</tag1>
        <tag2>stuff</tag2>
        <type>Float</type>
        <type>String</type>
        <type>Date</type>
        <tag3>stuff</tag3>
    </element>
</root>

我使用以下XSLT处理它:

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

    <xsl:template match="element">
        <xsl:element name="xs:element">
            <xsl:attribute name="type"><xsl:call-template name="type"/></xsl:attribute>
        </xsl:element>
    </xsl:template>

    <xsl:template name="type">
        <xsl:variable name="initialType" select="translate(type,' ','')"/>
        <xsl:choose>
            <xsl:when test="$initialType='String'">
                <xsl:text>xs:string</xsl:text>
            </xsl:when>
            <xsl:when test="$initialType='Date'">
                <xsl:text>xs:date</xsl:text>
            </xsl:when>
            <xsl:when test="$initialType='DateTime'">
                <xsl:text>xs:dateTime</xsl:text>
            </xsl:when>
            <xsl:when test="$initialType='Float'">
                <xsl:text>xs:float</xsl:text>
            </xsl:when>
            <xsl:when test="$initialType='Integer'">
                <xsl:text>xs:int</xsl:text>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$initialType"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

我得到了这个结果文件:

<?xml version="1.0" encoding="UTF-8"?>
    <xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"/>
    <xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"/>
    <xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:dateTime"/>
    <xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:float"/>

我的问题是只考虑第一个<type>标记。我想要的是将所有类型标记内容连接到输出的类型标记中,前面有一个符号,表示标记是一个聚合(如果适用)。 但是,为了避免人为地创建多种类型,标签的内容必须首先按字母顺序排序。在此示例中,<element>数字2和4都仅由Float,String和Date组成,尽管顺序不同。它们需要在输出中具有相同的类型。

以下输出是可以接受的:

<?xml version="1.0" encoding="UTF-8"?>
    <xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"/>
    <xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="unionxs:datexs:floatxs:string"/>
    <xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:dateTime"/>
    <xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="unionxs:datexs:floatxs:string"/>

我是XLST的新手,到目前为止我还没有设法接近所需的输出。我尝试过的代码就在下面,并且失败可怕,特别是因为我无法理解如何让<xsl:sort>工作:

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

    <xsl:template match="element">
        <xsl:element name="xs:element">
            <xsl:attribute name="type">
                    <xsl:apply-templates>
                      <xsl:sort select="."/>
                    </xsl:apply-templates>
                    <xsl:call-template name="type"/>
                </xsl:attribute>
        </xsl:element>
    </xsl:template>

    <xsl:template name="type">
        <xsl:choose>
            <xsl:when test="following-sibling::type">
                <xs:text>union</xs:text>
                <xsl:for-each select="following-sibling::type">
                    <xs:text>translate(type,' ','')</xs:text>
                </xsl:for-each>
            </xsl:when>
            <xsl:otherwise>
                <xsl:variable name="initialType" select="translate(type,' ','')"/>
                <xsl:choose>
                    <xsl:when test="$initialType='String'">
                        <xsl:text>xs:string</xsl:text>
                    </xsl:when>
                    <xsl:when test="$initialType='Date'">
                        <xsl:text>xs:date</xsl:text>
                    </xsl:when>
                    <xsl:when test="$initialType='DateTime'">
                        <xsl:text>xs:dateTime</xsl:text>
                    </xsl:when>
                    <xsl:when test="$initialType='Float'">
                        <xsl:text>xs:float</xsl:text>
                    </xsl:when>
                    <xsl:when test="$initialType='Integer'">
                        <xsl:text>xs:int</xsl:text>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="$initialType"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

2 个答案:

答案 0 :(得分:1)

只需对现有代码进行一些调整。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xsl:template match="element">
        <xsl:element name="xs:element">
            <xsl:attribute name="type">
                <xsl:variable name="sorted">
                    <xsl:for-each select="type">
                        <xsl:sort select="."/>
                        <xsl:copy-of select="."/>    
                    </xsl:for-each>
                </xsl:variable>
                <xsl:apply-templates select="$sorted/type"/>
            </xsl:attribute>
        </xsl:element>
    </xsl:template>

    <xsl:template match="type">
        <xsl:variable name="initialType" select="translate(., ' ', '')"/>
        <xsl:if test="count(preceding-sibling::type) = 0 and count(following-sibling::type) > 0">
            <xsl:text>union</xsl:text>
        </xsl:if>
        <!-- HINT remove if you dont want any seperator -->
        <xsl:if test="count(preceding-sibling::type) > 0">
            <xsl:text> </xsl:text>
        </xsl:if>
        <xsl:choose>
            <xsl:when test="$initialType='String'">
                <xsl:text>xs:string</xsl:text>
            </xsl:when>
            <xsl:when test="$initialType='Date'">
                <xsl:text>xs:date</xsl:text>
            </xsl:when>
            <xsl:when test="$initialType='DateTime'">
                <xsl:text>xs:dateTime</xsl:text>
            </xsl:when>
            <xsl:when test="$initialType='Float'">
                <xsl:text>xs:float</xsl:text>
            </xsl:when>
            <xsl:when test="$initialType='Integer'">
                <xsl:text>xs:int</xsl:text>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$initialType"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

请验证,对我来说,我得到了输出(参见XSLT中的内联提示):

<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="unionxs:date xs:float xs:string"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="xs:dateTime"/>
<xs:element xmlns:xs="http://www.w3.org/2001/XMLSchema" type="unionxs:date xs:float xs:string"/>

答案 1 :(得分:1)

我会这样做:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xsl:template match="element">
        <xsl:element name="xs:element">
            <xsl:attribute name="type">
                <xsl:apply-templates select="type">
                    <xsl:sort select="."/>
                </xsl:apply-templates>
            </xsl:attribute>
        </xsl:element>
    </xsl:template>

    <xsl:template match="type[translate(., ' ', '') = 'String']">xs:string</xsl:template>

    <xsl:template match="type[translate(., ' ', '') = 'Date']">xs:date</xsl:template>

    <xsl:template match="type[translate(., ' ', '') = 'DateTime']">xs:dateTime</xsl:template>

    <xsl:template match="type[translate(., ' ', '') = 'Float']">xs:float</xsl:template>

    <xsl:template match="type[translate(., ' ', '') = 'Integer']">xs:int</xsl:template>

    <xsl:template match="type">
        <xsl:value-of select="translate(., ' ', '')"/>
    </xsl:template>

</xsl:stylesheet>