-1

I'm new on XSLT. I want to sort the following xml segment by XSLT. Does anyone know how to sort the inner array values?

<Coordinates>
 <Array n="155" type="real">1909.090909090909 1894.7368421052631 1777.7777777777778 1923.076923076923 2000.0 3191.528925619835 3771.025641025641 4609.022727272727 6931.111111111111 7394.8611111111095 3149.4444444444443 4173.596491228071 6090.740740740741 7578.214285714285 7261.25 3369.7478260869566 5986.1621621621625 6515.15625 7138.875000000002 8225.714285714286 3224.5867768595035 6915.27027027027 8103.548387096775 6897.741935483871 8485.166666666666 3662.2988505747126 7968.2307692307695 7770.882352941177 6628.548387096775 8864.642857142857 3429.8863636363635 5785.285714285715 6576.428571428572 6791.8 8715.625 4015.2450980392155 7127.045454545455 6171.041666666667 9326.95652173913 10307.827586206897 3577.6136363636365 6820.000000000001 6308.913043478261 8907.0 9448.392857142857 3452.926829268293 7172.5 7280.0 8653.125 9277.692307692309 3108.3333333333335 4601.282051282052 6530.538461538462 8847.368421052632 8147.105263157895 3258.360655737705 7630.833333333335 6814.333333333333 5513.35294117647 9727.894736842105 2781.2500000000005 6974.21875 7172.5 6459.318181818182 8599.722222222223 3512.0454545454545 5203.5 7422.5 9705.454545454546 9217.631578947368 3608.7820512820513 6385.952380952381 9302.35294117647 6647.857142857143 8054.285714285715 ...
 </Array>
</Coordinates>

I want to sort the real values by ascending order.

Thanks in advance.

Abhishek Pandey
  • 13,302
  • 8
  • 38
  • 68
Shaner
  • 63
  • 5
  • Which XSLT processor will you be using? -- Hint: do a search for `tokenize`. – michael.hor257k Nov 07 '16 at 06:59
  • @michael.hor257k, could you please give me an example to do this? I need to copy the original xml to another firstly and then sort array values.` #sort array value ` – Shaner Nov 07 '16 at 09:20
  • Please answer my question. – michael.hor257k Nov 07 '16 at 14:32
  • Sorry. I'm using Java transformer to handle it. And I'd prefer to do it only in XSLT without parameter. – Shaner Nov 08 '16 at 02:13
  • This doesn't answer my question. See here how to identify the processor: http://stackoverflow.com/questions/25244370/how-can-i-check-which-xslt-processor-is-being-used-in-solr/25245033#25245033 – michael.hor257k Nov 08 '16 at 06:52
  • @michael.hor257k. Sorry, I'm a real new one and can not understand some concepts. It is my first try to solve something in my testing. – Shaner Nov 08 '16 at 10:02

3 Answers3

1

If you are using the Xalan-J processor, you can take advantage of the EXSLT str:tokenize() extension function and do simply:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="Array">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:for-each select="str:tokenize(., ' ')">
            <xsl:sort select="." data-type="number" order="ascending"/>
            <xsl:value-of select="."/>
            <xsl:text> </xsl:text>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Otherwise you will have to tokenize the values using a recursive named template, then convert the result to a node-set before you can sort it:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="Array">
    <xsl:variable name="values">
        <xsl:call-template name="tokenize">
            <xsl:with-param name="text" select="."/>
        </xsl:call-template>
    </xsl:variable>
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:for-each select="exsl:node-set($values)/value">
            <xsl:sort select="." data-type="number" order="ascending"/>
            <xsl:value-of select="."/>
            <xsl:text> </xsl:text>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

<xsl:template name="tokenize">
    <xsl:param name="text"/>
    <xsl:param name="delimiter" select="' '"/>
        <xsl:variable name="token" select="substring-before(concat($text, $delimiter), $delimiter)" />
        <xsl:if test="$token">
            <value>
                <xsl:value-of select="$token"/>
            </value>
        </xsl:if>
        <xsl:if test="contains($text, $delimiter)">
            <!-- recursive call -->
            <xsl:call-template name="tokenize">
                <xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
            </xsl:call-template>
        </xsl:if>
</xsl:template>

</xsl:stylesheet>
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
-1

One solution is to form a variable where each tag contains value. And then you can sort it by method , which works for number in xslt 1.0 too. As i can see, your values here are separated by a space.

Igor R.
  • 17
  • 4
  • Even in xslt 1.0 you'd need a node-set() function to do this, I think - that's probably why @michael-hor257k is asking for the processor. – Tom Hillman Nov 07 '16 at 23:49
  • @Igor R.Thank you so much. I like your answer. And I have tried this as [xsl: how to split strings?](http://stackoverflow.com/questions/4845660/xsl-how-to-split-strings). But after splitting, sort can not take effect for priority and conflict reasons. Do you know how to sort after splitting? – Shaner Nov 08 '16 at 02:23
  • This is not an answer - please delete it. A speculation about how a problem *might* be solved belongs in a comment at best. – michael.hor257k Nov 09 '16 at 12:34
-1

ok, here is my solution. credit for a part goes to Does XSLT have a Split() function?

    <xsl:template match="/">
    <xsl:variable name="raw-data">
      <xsl:value-of select="Coordinates/Array"/>
    </xsl:variable>

    <xsl:variable name="ids">
      <xsl:if test="$raw-data">
        <xsl:call-template name="output-tokens">
          <xsl:with-param name="list" select="$raw-data" />
        </xsl:call-template>
      </xsl:if>
    </xsl:variable>

    <xsl:for-each select="msxsl:node-set($ids)/id">
      <xsl:sort data-type="number" order="descending" select="."/>
        <xsl:copy-of select="."/>
    </xsl:for-each>

  </xsl:template>

  <xsl:template name="output-tokens">
    <xsl:param name="list" />
    <xsl:variable name="newlist" select="concat(normalize-space($list), ' ')" />
    <xsl:variable name="first" select="substring-before($newlist, ' ')" />
    <xsl:variable name="remaining" select="substring-after($newlist, ' ')" />
    <id>
      <xsl:value-of select="$first" />
    </id>
    <xsl:if test="$remaining">
      <xsl:call-template name="output-tokens">
        <xsl:with-param name="list" select="$remaining" />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

p.s. edited - now with sort

Community
  • 1
  • 1
Igor R.
  • 17
  • 4