Слияние двух последовательностей в xsl - PullRequest
2 голосов
/ 29 апреля 2011
  • Две последовательности элементов, которые сортируются по возрастанию. , xsl выводит одну последовательность, содержащую все элементы, и сортирует их все больше.

вход:

<!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>

вывод должен быть:

<?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>

вот мой xsl, результат неверный, не могли бы вы показать это мне ??

<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"  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>

Ответы [ 2 ]

4 голосов
/ 29 апреля 2011
    <?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>

Если вы не хотите использовать xsl:sort и хотите использовать свою таблицу стилей и пользовательский шаблон «слияния», необходимо выполнить несколько настроек, чтобыработать с образцом ввода.Ниже приведена исправленная версия с некоторыми встроенными комментариями, объясняющими, где были сделаны корректировки:

<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>
1 голос
/ 30 апреля 2011

Используйте @data-type="number" для сортировки:

<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>
...