我需要添加缺少的节点,然后排序包括添加的新节点

时间:2017-10-06 05:47:43

标签: sorting xslt add multipass

我有一个输入XML,我需要使用XSLT 2.0进行转换。

这是我的输入xml

<root>
         <person>
            <LastName>yyyyy</LastName>
            <FirstName>xxxx</FirstName>
            <profession>IT/xx</profession>
            <area>0000</area>
            <email>xxx.yyy@xxx.com</email>
            <Address>aaaaaaaaa,bbbbbbbbbbbb,cccccccccc,dddddddddd,eeeeeeee</Address>
            <sex>male</sex>
         </person>
      </root>

我的输入xml缺少一些节点。例如(移动,按照xsd强制使用的国家/地区)。现在,我需要添加这两个节点(作为空节点)然后我需要排序,包括那两个节点。

排序顺序:FirstName,LastName,电子邮件,性别,专业,手机,地址,地区,国家/地区;

最终输出xml应为:

<root>
         <person>
            <FirstName>xxxx</FirstName>
            <LastName>yyyyy</LastName>
            <email>xxx.yyy@xxx.com</email>
            <sex>male</sex>
            <profession>IT/xx</profession>
            <mobile/>
            <Address>aaaaaaaaa,bbbbbbbbbbbb,cccccccccc,dddddddddd,eeeeeeee</Address>
            <area>0000</area>
            <country/>
         </person>
      </root>

我尝试使用以下XSLT:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="pOrderedNames" select="'FirstName,LastName,email,sex,profession,mobile,Address,area,country'"/>

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

    <xsl:template match="person[not(./country)]" mode="country">
        <xsl:element name="country" />
    </xsl:template>

    <xsl:template match="person[not(./mobile)]" mode="mobile">
        <xsl:element name="mobile" />
    </xsl:template>

    <xsl:template match="*" mode="sorter">
        <xsl:copy>
            <xsl:apply-templates>
                <xsl:sort data-type="number" select="string-length(substring-before($pOrderedNames,concat(',',name(),',')))"/>  
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="person">
        <xsl:copy>
            <xsl:apply-templates select="node()"/>
            <xsl:apply-templates  select="self::node()" mode="mobile"/>
            <xsl:apply-templates  select="self::node()" mode="country"/>
            <xsl:apply-templates  select="self::node()" mode="email"/>
            <xsl:apply-templates  select="self::node()" mode="sex"/>    
            <xsl:apply-templates select="self::*" mode="sorter"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

使用上面的XSLT,它将按以下方式进行转换:

<root>
   <person>
      <LastName>yyyyy</LastName>
      <FirstName>xxxx</FirstName>
      <profession>IT/xx</profession>
      <area>0000</area>
      <email>xxx.yyy@xxx.com</email>
      <Address>aaaaaaaaa,bbbbbbbbbbbb,cccccccccc,dddddddddd,eeeeeeee</Address>
      <sex>male</sex>
      <mobile/>
      <country/>yyyyyxxxxIT/xx0000xxx.yyy@xxx.comaaaaaaaaa,bbbbbbbbbbbb,cccccccccc,dddddddddd,eeeeeeeemaleyyyyyxxxxIT/xx0000xxx.yyy@xxx.comaaaaaaaaa,bbbbbbbbbbbb,cccccccccc,dddddddddd,eeeeeeeemale<person>
         <FirstName>xxxx</FirstName>
         <LastName>yyyyy</LastName>
         <email>xxx.yyy@xxx.com</email>
         <sex>male</sex>
         <profession>IT/xx</profession>
         <Address>aaaaaaaaa,bbbbbbbbbbbb,cccccccccc,dddddddddd,eeeeeeee</Address>
         <area>0000</area>
      </person>
   </person>
</root>

请有人帮帮我。

先谢谢。

1 个答案:

答案 0 :(得分:0)

以下是您的方法的改编,它使用模板创建新元素,并通过将各种apply-templates包装到perform-sort中来对它们进行排序:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">   

    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="pOrderedNames"
        select="'FirstName,LastName,email,sex,profession,mobile,Address,area,country'"/>
    <xsl:param name="pNameOrder" select="tokenize($pOrderedNames, ',')"/>

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

    <xsl:template match="person" mode="country">
        <country/>
    </xsl:template>

    <xsl:template match="person" mode="mobile">
        <mobile/>
    </xsl:template>

    <xsl:template match="person">
        <xsl:copy>
            <xsl:perform-sort>
                <xsl:sort select="index-of($pNameOrder, local-name())"/>
                <xsl:apply-templates select="*"/>
                <xsl:apply-templates select=".[not(country)]" mode="country"/>
                <xsl:apply-templates select=".[not(mobile)]" mode="mobile"/>
            </xsl:perform-sort>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

我不确定是否需要创建模板和模式的新元素,简单的<xsl:if test="not(mobile)"><mobile/></xsl:if>就足够了,但使用模式是可行的方法。