XSLT sort by tag name and attribute value

前端 未结 3 1499
挽巷
挽巷 2020-12-19 17:16

I\'m a noob with XSLT, so please excuse my ignorance... I\'m trying to sort a simple XML file by attribute value and tag name, but I struggle in accessing the value of the a

相关标签:
3条回答
  • 2020-12-19 17:43

    You can use multiple xsl:sort instructions, for example:

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

    and since the default data-type is "text" and the default order is "ascending" this gives the desired output.

    Edit

    This is strange, because for the following XML:

    <a>
        <b attribute="e" optionalAttr="fg"></b>
        <b attribute="b"></b>
        <d attribute="a"></d>
        <c></c>
    </a>
    

    and the XSL above, I get this result:

    <a>
        <b attribute="b"></b>
        <b attribute="e" optionalAttr="fg"></b>
        <c></c>
        <d attribute="a"></d>
    </a>
    

    This includes the desired optional attribute but the order is different to the XML in the edited question (<c></c> is in a different position).

    0 讨论(0)
  • 2020-12-19 17:43

    This XSLT 2.0 transformation performs sorting by element name and multiple attributes nameand value:

    <xsl:stylesheet version="2.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xs="http://www.w3.org/2001/XMLSchema"
     xmlns:my="my:my">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
        <xsl:template match="node()|@*">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*">
                    <xsl:sort select="name()" />
                    <xsl:sort select="my:attributeScore(.)" />
                </xsl:apply-templates>
            </xsl:copy>
        </xsl:template>
    
        <xsl:function name="my:attributeScore" as="xs:string">
          <xsl:param name="pThis" as="node()"/>
    
          <xsl:variable name="vScore">
              <xsl:for-each select="$pThis/@*">
               <xsl:sort select="name()"/>
    
               <xsl:value-of select="concat(name(),'+',.)"/>
              </xsl:for-each>
              <xsl:text>|</xsl:text>
          </xsl:variable>
    
          <xsl:sequence select="string-join($vScore, '')"/>
        </xsl:function>
    </xsl:stylesheet>
    

    when applied on this XML document (the provided one, but added multiple attributes):

    <a>
        <b attribute="e" x="y"></b>
        <b attribute="e" x="x"></b>
        <b attribute="b"></b>
        <d attribute="a"></d>
        <c></c>
    </a>
    

    the correctly sorted result is produced:

    <a>
       <b attribute="b"/>
       <b attribute="e" x="x"/>
       <b attribute="e" x="y"/>
       <c/>
       <d attribute="a"/>
    </a>
    
    0 讨论(0)
  • 2020-12-19 17:59

    I just saw this question and as I'm new at xpath and XSL thought i'll give it a shot.

    I seem to have come up with a completely different solution.

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="*">
        <xsl:copy>
            <xsl:apply-templates select="* | @*">
                <xsl:sort select="not(@*)" order="ascending" data-type="number"/>
                <xsl:sort select="@*"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*/@*">
        <xsl:copy>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="text()[not(string-length(normalize-space()))]"/>
    <xsl:template match="*/text()[normalize-space()]">
        <xsl:value-of select="normalize-space()"/>
    </xsl:template>
    

    It does depend on how you want the attributes to be order...

    Sample 1:

    <?xml version="1.0" encoding="utf-8" ?>
    <a>
        <b attribute="e" ></b>
        <b attribute="b" ></b>
        <c></c>
        <d attribute="a"></d>
    </a>
    

    Result 1

    <a>
      <d attribute="a" />
      <b attribute="b" />
      <b attribute="e" />
      <c />
    </a>
    

    Sample 2

    <?xml version="1.0" encoding="utf-8" ?>
    <a>
        <b attribute="e" ></b>
        <b attribute="b" optionalAttr="fg"></b>
        <c></c>
        <d attribute="a"></d>
    </a>
    

    Result 2

    <?xml version="1.0" encoding="utf-8"?>
    <a>
      <d attribute="a" />
      <b attribute="b" optionalAttr="fg" />
      <b attribute="e" />
      <c />
    </a>
    

    Just wondering if anyone could see anything wrong with this approach?

    Thank you in advanced

    0 讨论(0)
提交回复
热议问题