Проблема пользовательской сортировки с использованием XSL 1.0 - PullRequest
1 голос
/ 08 октября 2019

Я пытаюсь отсортировать элементы в XML на основе пользовательских требований сортировки. Сначала мне нужно отсортировать на основе 1-го символа в VerificationCode в порядке V, P, U, A, C, R. Затем мне нужно отсортировать на основе числовых во 2 и 3 символов.

Образец xml, который я использую:

<ns3:Response xmlns:ns3="http://www.example.org">
   <ns3:Codes>
      <ns3:Name>US</ns3:Name>
      <ns3:VerificationCode>A42</ns3:VerificationCode>
   </ns3:Codes>
   <ns3:Codes>
      <ns3:Name>CH</ns3:Name>
      <ns3:VerificationCode>V54</ns3:VerificationCode>
   </ns3:Codes>
   <ns3:Codes>
      <ns3:Name>IN</ns3:Name>
      <ns3:VerificationCode>U14</ns3:VerificationCode>
   </ns3:Codes>
   <ns3:Codes>
      <ns3:Name>MY</ns3:Name>
      <ns3:VerificationCode>V84</ns3:VerificationCode>
   </ns3:Codes>
   <ns3:Codes>
      <ns3:Name>MX</ns3:Name>
      <ns3:VerificationCode>C34</ns3:VerificationCode>
   </ns3:Codes>
</ns3:Response>

Для 1-го уровня XSL сорта I, который у меня есть, как показано ниже. Но он ничего не делает.

<xsl:stylesheet version="1.0" xmlns:ns0="http://www.example.org" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:template match="*">
      <xsl:variable name="sortOrder1" select="'|V|P|U|A|C|R'" />
      <xsl:apply-templates select="ns0:Codes">
        <xsl:sort select="string-length(substring-before($sortOrder1, concat('|', substring(ns0:VerificationCode,1,1), '|')))" data-type="number"/>
      </xsl:apply-templates>
   </xsl:template>
   <xsl:template match="/">
      <ns0:Response>
         <xsl:copy-of select="/ns0:Response"/>
      </ns0:Response>
   </xsl:template>
</xsl:stylesheet>

Ниже ожидаемый результат

<ns3:Response xmlns:ns3="http://www.example.org">
   <ns3:Codes>
      <ns3:Name>MY</ns3:Name>
      <ns3:VerificationCode>V84</ns3:VerificationCode>
   </ns3:Codes>
   <ns3:Codes>
      <ns3:Name>CH</ns3:Name>
      <ns3:VerificationCode>V54</ns3:VerificationCode>
   </ns3:Codes>
   <ns3:Codes>
      <ns3:Name>IN</ns3:Name>
      <ns3:VerificationCode>U14</ns3:VerificationCode>
   </ns3:Codes>   
   <ns3:Codes>
      <ns3:Name>US</ns3:Name>
      <ns3:VerificationCode>A42</ns3:VerificationCode>
   </ns3:Codes>
   <ns3:Codes>
      <ns3:Name>MX</ns3:Name>
      <ns3:VerificationCode>C34</ns3:VerificationCode>
   </ns3:Codes>
</ns3:Response>

Ответы [ 2 ]

3 голосов
/ 08 октября 2019

Вы не можете использовать copy-of в корневом узле, если хотите применить шаблоны, а также просто сопоставить этот конкретный элемент Response:

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

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

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

   <xsl:template match="ns0:Response">
      <xsl:copy>
          <xsl:variable name="sortOrder1" select="'|V|P|U|A|C|R'" />
          <xsl:apply-templates select="ns0:Codes">
            <xsl:sort select="string-length(substring-before($sortOrder1, concat('|', substring(ns0:VerificationCode,1,1), '|')))" data-type="number"/>
          </xsl:apply-templates>          
      </xsl:copy>
   </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty -development.net / 6rewNxR , однако, имеет несколько иной порядок, чем тот, который вы показали, поскольку значение V54 на входе предшествует значению V84.

1 голос
/ 08 октября 2019

Мне понадобилось время, чтобы понять, что вы хотите. Вы можете упростить свою жизнь, используя несколько операторов сортировки, только один шаблон и ни одно из этих пространств имен.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
   <xsl:template match="/Response">
      <xsl:variable name="sortOrder" select="'VPUACR'" />
      <Response>
        <xsl:for-each select="Codes">
          <xsl:sort select="string-length(substring-before($sortOrder, substring(VerificationCode/text(), 1, 1)))"/>
          <xsl:sort select="substring(VerificationCode/text(), 1)" data-type="number"/>
          <xsl:copy-of select="."/>
        </xsl:for-each>
      </Response>
   </xsl:template>
</xsl:stylesheet>

Fiddle here

...