Francesco Irrera
Francesco Irrera

Reputation: 473

Xslt nested sorting

I'm trying to sort alphabetically fields (in this case VICINITY), but if not exist (VICINITY), I need to consider another field (ITA_LIGHT_NAME), thereby creating two nested sort.

I create this xslt:

<xsl:text>List A<xsl:text>
<xsl:for-each select="//VICINITY[not(. = preceding::VICINITY)]">
    <xsl:sort select="." data-type="text" order="ascending"/>
    <xsl:sort select="preceding-sibling::ITA_LIGHT_NUMBER" data-type="text" order="ascending"/>
        <xsl:variable name ="localita" select="."/>
        <xsl:value-of select="."/>
        <br/>           
</xsl:for-each>
<br/>

<xsl:text>List B<xsl:text>
<xsl:for-each select="//ITA_LIGHT_NAME[not(. = preceding::ITA_LIGHT_NAME)]">
    <xsl:if test="not(preceding-sibling::VICINITY)">
        <xsl:value-of select="."/><br/>
    </xsl:if>
</xsl:for-each>

This give two result (List A and List B divided in two different list):

List A

ANCONA     (Only one time)
GENOVA
MESSINA
VENEZIA

List B

Capo Peloro 
Capo Rizzuto (Only one time)

But, I really would like as final output a single list(sorted alphabetically):

ANCONA     (Only one time)
Capo Peloro
Capo Rizzuto (Only one time)
GENOVA
MESSINA
VENEZIA

Practically, should work in the following way: Order alphabetically by VICINITY(without repetition) if exist, if not exist, order by ITA_LIGHT_NAME(without repetition).

Thi is my XML, can you Help to simulate this output:

<SECTION_CONTENT_LIST>
    <SECTION_CONTENT_LIST_ITEM>
        <NTC_LIGHTLISTPRODUCT>
            <ITA_LIGHT_NUMBER>3921.9</ITA_LIGHT_NUMBER> 
            <VICINITY>ANCONA</VICINITY>
            <ITA_LIGHT_NAME>Installazioni 1</ITA_LIGHT_NAME>
        </NTC_LIGHTLISTPRODUCT>
    </SECTION_CONTENT_LIST_ITEM>    
    <SECTION_CONTENT_LIST_ITEM>
        <NTC_LIGHTLISTPRODUCT>
            <ITA_LIGHT_NUMBER>3924</ITA_LIGHT_NUMBER>
            <VICINITY>ANCONA</VICINITY>
            <ITA_LIGHT_NAME>Installazioni 2</ITA_LIGHT_NAME>
        </NTC_LIGHTLISTPRODUCT>
    </SECTION_CONTENT_LIST_ITEM>
    <SECTION_CONTENT_LIST_ITEM>
        <NTC_LIGHTLISTPRODUCT>
            <ITA_LIGHT_NUMBER>1577</ITA_LIGHT_NUMBER>
            <VICINITY>GENOVA</VICINITY>
            <ITA_LIGHT_NAME>Granarolo</ITA_LIGHT_NAME>
        </NTC_LIGHTLISTPRODUCT>
    </SECTION_CONTENT_LIST_ITEM>
    <SECTION_CONTENT_LIST_ITEM>
       <NTC_LIGHTLISTPRODUCT>
           <ITA_LIGHT_NUMBER>2746</ITA_LIGHT_NUMBER>
           <VICINITY>MESSINA</VICINITY>
           <ITA_LIGHT_NAME>Meda elastica</ITA_LIGHT_NAME>
       </NTC_LIGHTLISTPRODUCT>
    </SECTION_CONTENT_LIST_ITEM>
    <SECTION_CONTENT_LIST_ITEM>    
        <NTC_LIGHTLISTPRODUCT>
            <ITA_LIGHT_NUMBER>4231.4</ITA_LIGHT_NUMBER>
            <VICINITY>VENEZIA</VICINITY>
            <ITA_LIGHT_NAME>Segnale da nebbia</ITA_LIGHT_NAME>
        </NTC_LIGHTLISTPRODUCT>
    </SECTION_CONTENT_LIST_ITEM>
    <SECTION_CONTENT_LIST_ITEM>
        <NTC_LIGHTLISTPRODUCT>
            <ITA_LIGHT_NUMBER>2736</ITA_LIGHT_NUMBER>
            <ITA_LIGHT_NAME>Capo Peloro</ITA_LIGHT_NAME>
        </NTC_LIGHTLISTPRODUCT>
    </SECTION_CONTENT_LIST_ITEM>
    <SECTION_CONTENT_LIST_ITEM>
        <NTC_LIGHTLISTPRODUCT>
            <ITA_LIGHT_NUMBER>3396</ITA_LIGHT_NUMBER>             
            <ITA_LIGHT_NAME>Capo Rizzuto</ITA_LIGHT_NAME>
        </NTC_LIGHTLISTPRODUCT>
    </SECTION_CONTENT_LIST_ITEM>
    <SECTION_CONTENT_LIST_ITEM>
        <NTC_LIGHTLISTPRODUCT>
            <ITA_LIGHT_NUMBER>3399</ITA_LIGHT_NUMBER>             
            <ITA_LIGHT_NAME>Capo Rizzuto</ITA_LIGHT_NAME>
        </NTC_LIGHTLISTPRODUCT>
    </SECTION_CONTENT_LIST_ITEM>
</SECTION_CONTENT_LIST>

Upvotes: 0

Views: 449

Answers (2)

Francesco Irrera
Francesco Irrera

Reputation: 473

I am starting from the solution of michael.hor257k (directed me to a correct solution), I am try it using http://xslttest.appspot.com/

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

<xsl:key name="k" match="ITA_LIGHT_NUMBER" use="following-sibling::VICINITY | following-sibling::ITA_LIGHT_NAME[not(../preceding-sibling::VICINITY)]" />

<xsl:template match="/">
<xsl:for-each select="//ITA_LIGHT_NUMBER[count(. | key('k', following-sibling::VICINITY | following-sibling::ITA_LIGHT_NAME[not(../VICINITY)])[1]) = 1]">
    <xsl:sort select="following-sibling::VICINITY | following-sibling::ITA_LIGHT_NAME[not(../preceding-sibling::VICINITY)]"/>
    <xsl:value-of select="following-sibling::VICINITY | following-sibling::ITA_LIGHT_NAME[not(../preceding-sibling::VICINITY)]"/>
    <xsl:if test="position()!=last()">
        <xsl:text>&#10;</xsl:text>
        <br/>
    </xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Thanks Michael.hor257k your collaboration has been invaluable.

Upvotes: 1

michael.hor257k
michael.hor257k

Reputation: 116992

Practically, should work in the following way: Order alphabetically by VICINITY(without repetition) if exist, if not exist, order by ITA_LIGHT_NAME(without repetition).

No, it cannot work that way. What you need to do first is get only distinct records (considering VICINITY if it exists, ITA_LIGHT_NAME otherwise), then sort the results by the same.

The first step is done through a method known as Muenchian grouping - read about it here: http://www.jenitennison.com/xslt/grouping/muenchian.html

Note also that your input is missing a root element. Once you add it, you can try:

XSLT 1.0

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

<xsl:key name="k" match="NTC_LIGHTLISTPRODUCT" use="VICINITY | ITA_LIGHT_NAME[not(../VICINITY)]" />

<xsl:template match="/">
    <xsl:for-each select="root/NTC_LIGHTLISTPRODUCT[count(. | key('k', VICINITY | ITA_LIGHT_NAME[not(../VICINITY)])[1]) = 1]">
        <xsl:sort select="VICINITY | ITA_LIGHT_NAME[not(../VICINITY)]"/>
        <xsl:value-of select="VICINITY | ITA_LIGHT_NAME[not(../VICINITY)]"/>
        <xsl:if test="position()!=last()">
            <xsl:text>&#10;</xsl:text>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

to obtain:

ANCONA
Capo Peloro
Capo Rizzuto
GENOVA
MESSINA
VENEZIA

Upvotes: 1

Related Questions