开发者

Merging two Sequences in xsl

  • The two sequences of elements which are sorted by increasing. , xsl outputs one sequence containing all the items and sorted them increasingly.

input:

<!DOCTYPE lists SYSTEM "list.dtd">

<numbers>
<list>
   <num val="2"/>
   <num val="5"/>
   <num val="8"/>
   <num val="12"/>
   <num val="20"/>
   <num val="32"/>
</list>
<list>
   <num val="4"/>
   <num val="7"/>
   <num val="10"/>
   <num val="29"/>
   <num val="30"/>
</list>
</numbers>

the output should be:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE lists SYSTEM "list.dtd">
<numbers>
<list>
   <num val="2"/>
   <num val="4"/>
   <num val="5"/>
   <num val="7"/>
   <num val="8"/>
   <num val="10"/>
   <num val="12"/>
   <num val="20"/>
   <num val="29"/>
   <num val="30"/>
   <num val="32"/>
</list>
</numbers>

here is my xsl ,the result is wrong ,could you show it for me??

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

 <xsl:output method="xml"  version="1.0" encoding="UTF-8" indent ="yes"/>

<xsl:template match="/">
<xsl:apply-templates/>
 <xsl:text>&#10;</xsl:text>
 </xsl:template>

 <xsl:template match="lists">
  <xsl:copy>
  <list>
    <xsl:call-template name="merge">
      <xsl:with-param name ="num1" select="list[1]/item" as="element(item)*"/>
      <xsl:with-param name="num2" select ="list[2]/item" as="element(item)*"/>
    </xsl:call-template>
   </list>
  </xsl:copy>
</xsl:template>

<xsl:template name="merge" as="element(item)*">
<xsl:param name="num1" as="element(item)*"/>
<xsl:param name="num2" as="element(item)*"/>
<xsl:choose>
  <xsl:when test="empty($num1)">
    <xsl:sequence select="$num2"/>
  </xsl:when>
  <xsl:when test="empty($num2)">
    <xsl:sequence select="$num1"/>
   </xsl:when>
      <xsl:when test="$num2[1]/@val ge $num1[1]/@val">
      <xsl:sequence select="$num1[1]"/>
      <xsl:call-template name="merge">
        <xsl:with-param name="num1"  开发者_StackOverflow中文版select="$num1[position()>1]"/>
        <xsl:with-param name="num2" select="$num2[1]"/>
      </xsl:call-template>
    </xsl:when>
      <xsl:otherwise>
        <xsl:sequence select="$num2[1]"/>
        <xsl:call-template name="merge">
          <xsl:with-param name="num1" select="$num1[1]"/>
          <xsl:with-param name="num2"  select="$num2[position()>1]"/>
        </xsl:call-template>
      </xsl:otherwise>

   </xsl:choose>
  </xsl:template>
</xsl:transform>


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

    <xsl:template match="numbers">
        <xsl:copy>
         <list>
            <!--process all of the num elements -->
            <xsl:apply-templates select="list/num">
            <!--Sort the num elements by @val, as number to ensure proper sort order-->
                <xsl:sort select="number(@val)"/>
            </xsl:apply-templates>
         </list>
        </xsl:copy>
    </xsl:template>

    <!--Identity template - copies content forward by default -->
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()" />
            </xsl:copy>
        </xsl:template>

    </xsl:stylesheet>

If you don't want to use xsl:sort, and want to use your stylesheet and custom "merge" template, there are a couple of adjustments that you need to make in order for it to work with the sample input. Below is a corrected version with some inline comments explaining where the adjustments were made:

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

    <xsl:output method="xml"  version="1.0" encoding="UTF-8" indent ="yes"/>

    <xsl:template match="/">
        <xsl:apply-templates/>
        <xsl:text>&#10;</xsl:text>
    </xsl:template>

    <!--Issue#1: This was matching on "lists" -->
    <xsl:template match="numbers">
        <xsl:copy>
            <list>
                <xsl:call-template name="merge">
                    <!--Issue#2: these parameters were restricted to "item", not "num" -->
                    <xsl:with-param name ="num1" select="list[1]/num" as="element(num)*"/>
                    <xsl:with-param name="num2" select ="list[2]/num" as="element(num)*"/>
                </xsl:call-template>
            </list>
        </xsl:copy>
    </xsl:template>

    <!--Issue#3: these output restricted to "item", not "num" -->
    <xsl:template name="merge" as="element(num)*">
        <!--Issue#4: these parameters were restricted to "item", not "num" -->
        <xsl:param name="num1" as="element(num)*"/>
        <xsl:param name="num2" as="element(num)*"/>

        <xsl:choose>
            <xsl:when test="empty($num1)">
                <xsl:sequence select="$num2"/>
            </xsl:when>
            <xsl:when test="empty($num2)">
                <xsl:sequence select="$num1"/>
            </xsl:when>
            <!--Issue#5: These values need to be evaluated as numbers, string compare will give you bad results(e.g. "10" is less than "8") -->
            <xsl:when test="number($num2[1]/@val) ge number($num1[1]/@val)"> 
                <xsl:sequence select="$num1[1]"/>
                <xsl:call-template name="merge">
                    <xsl:with-param name="num1"  select="$num1[position()>1]"/>
                    <xsl:with-param name="num2" select="$num2"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:sequence select="$num2[1]"/>
                <xsl:call-template name="merge">
                    <xsl:with-param name="num1" select="$num1"/>
                    <xsl:with-param name="num2"  select="$num2[position()>1]"/>
                </xsl:call-template>
            </xsl:otherwise>

        </xsl:choose>
    </xsl:template>
</xsl:transform>


Use @data-type="number" to do the sorting:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:strip-space elements="*"/>
  <xsl:output indent="yes" doctype-system="list.dtd" />

  <xsl:template match="numbers">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <list>
        <xsl:apply-templates select="list/num">
          <xsl:sort select="@val" data-type="number"/>
        </xsl:apply-templates>
      </list>
    </xsl:copy>
  </xsl:template>

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

</xsl:stylesheet>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜