1

I've the below XML.

<?xml version="1.0" encoding="UTF-8"?>
    <main.line>
            <main>
                <name>Mohamad</name>
                <job.title prefix="no">B</job.title>
            </main>
            <main>
                <name>David</name>
                <job.title prefix="no">B</job.title>
            </main>
            <main>
                <name>Hashim</name>
                <job.title prefix="no">B</job.title>
            </main>
            <main>
                <name>Anthony</name>
                <job.title prefix="no">C</job.title>
            </main>
        </main.line>

Here i'm trying to print the name and job.title in the below way.

If the job.title is same and there are more than two similar occurrences, the name has to be print with a comma and the last name should be printed with an and along with the job.title concatenated with A at start.(This is a bit confusing but my output below will make this clear).

If there are two cases then it should be printed with and but no comma

If there is no such case, the name should be printed directly along with the job.title.

The desired output is as below.

Mohamad, David and Hashim BA, Anthony C

The XSLT I tried is as below.

<xsl:template match="main.line">
    <xsl:for-each select="main  ">
        <xsl:choose>
            <xsl:when test="./job.title=following-sibling::main/job.title">
                <xsl:choose>
                    <xsl:when test="./job.title='A' or 'B' or 'C' or 'D' or 'E'">
                        <xsl:value-of select="./name"/>
                        <xsl:text>, </xsl:text>
                        <xsl:value-of select="following-sibling::main[1]/name"/>
                        <xsl:text> </xsl:text>
                        <xsl:value-of select="./job.title"/>
                        <xsl:text>A</xsl:text>
                        <xsl:text> </xsl:text>
                    </xsl:when>
                </xsl:choose>
            </xsl:when>
            <xsl:otherwise>
                <xsl:choose>
                    <xsl:when test="not(position() = last()) and fn:not(fn:position()=1)">
                        <xsl:text>, </xsl:text>
                    </xsl:when>
                    <xsl:when test="position()=last() and fn:not(fn:position()=1)">
                        <xsl:text> and </xsl:text>
                    </xsl:when>
                </xsl:choose>
                <xsl:value-of select="name"/>
                <xsl:text> </xsl:text>
                <xsl:value-of select="job.title"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
</xsl:template>

But the output that i get currently is

Mohamad, David BA David, Hashim BA , Hashim B and Anthony C.

please let me know where did i go wrong and how i can get the desired output.

Thanks

user3872094
  • 3,269
  • 8
  • 33
  • 71

1 Answers1

1

I would use for-each-group with group-by (if you want to group all main elements with the same job.title) or group-adjacent (if you want to group only siblings with the same job.title), here is an example using group-by:

<xsl:template match="main.line">
  <xsl:for-each-group select="main" group-by="job.title">
    <xsl:value-of select="if (count(current-group()) eq 1)
                          then concat(name, ' ', job.title)
                          else if (count(current-group()) eq 2)
                               then concat(current-group()[1]/name, ' and ', current-group()[2]/name, job.title, 'A')
                               else concat(string-join(current-group()[position() lt (last() - 1)]/name, ', '), ', ',
                                           current-group()[last() - 1]/name, ' and ', current-group()[last()]/name, ' ', job.title, 'A')"/>
    <xsl:if test="position() != last()">, </xsl:if>
  </xsl:for-each-group>
</xsl:template>
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • Hi Marthin, this is awesome, worked like charm. Just a quick Question, if i have multiple `C`, it should be shown as `BC`, can i edit the above adding an extra `if` clause or am i supposed to use a `choose`? – user3872094 Dec 01 '14 at 07:55
  • It should be possible to add an `if` clause. – Martin Honnen Dec 01 '14 at 09:36
  • Hi @Martin, if you don't mind can you please have a look at this post and help me, http://stackoverflow.com/questions/27164342/match-uncaught-though-declared-in-xsl?noredirect=1#comment42826217_27164342. Thanks – user3872094 Dec 04 '14 at 11:38