0

I have an xml output as follows (see - 'Current') and there is a requirement to change the order of some of the elements so that it appears as below (see - Required). Currently some XSLT is being used to transform an initial raw output from an access DB to reach get the 'Current' example below. Would it be possible to change the ordering using XSLT?

CURRENT

<DFileUpload>
<Sessions>
    <Session>
        <SessionId>ABC181_1483</SessionId>
        <CaseId>KIBB1</CaseId>
        <SessionDate>2018-01-22</SessionDate>
        <ServiceTypeId>1</ServiceTypeId>
        <TotalNumberOfUnidentifiedClients>0</TotalNumberOfUnidentifiedClients>
        <FeesCharged>0</FeesCharged>
        <MoneyBusinessCommunityEducationWorkshopCode>0</MoneyBusinessCommunityEducationWorkshopCode>
        <InterpreterPresent>0</InterpreterPresent>
        <TimeMinutes>0</TimeMinutes>
        <TotalCost>0</TotalCost>
        <Quantity>1</Quantity>
        <Topic>OTHER</Topic>
        <SessionClients>
            <SessionClient>
                <ClientId>BSAC</ClientId>
                <ParticipationCode>Client</ParticipationCode>
            </SessionClient>
        </SessionClients>
    </Session>

    <Session>
        <SessionId>ABC181_1484</SessionId>
        <CaseId>KIBB2</CaseId>
        <SessionDate>2018-01-30</SessionDate>
        <ServiceTypeId>1</ServiceTypeId>
        <TotalNumberOfUnidentifiedClients>0</TotalNumberOfUnidentifiedClients>
        <FeesCharged>0</FeesCharged>
        <MoneyBusinessCommunityEducationWorkshopCode>0</MoneyBusinessCommunityEducationWorkshopCode>
        <InterpreterPresent>0</InterpreterPresent>
        <TimeMinutes>0</TimeMinutes>
        <TotalCost>0</TotalCost>
        <Quantity>1</Quantity>
        <Topic>OTHER</Topic>
        <SessionClients>
            <SessionClient>
                <ClientId>BSAC</ClientId>
                <ParticipationCode>Client</ParticipationCode>
            </SessionClient>
        </SessionClients>
    </Session>
<Sessions/>

REQUIRED

<DFileUpload>
<Sessions>
    <Session>
        <SessionId>ABC181_1483</SessionId>
        <CaseId>KIBB1</CaseId>
        <SessionDate>2018-01-22</SessionDate>
        <ServiceTypeId>1</ServiceTypeId>
        <TotalNumberOfUnidentifiedClients>0</TotalNumberOfUnidentifiedClients>
        <FeesCharged>0</FeesCharged>
        <MoneyBusinessCommunityEducationWorkshopCode>0</MoneyBusinessCommunityEducationWorkshopCode>
        <InterpreterPresent>0</InterpreterPresent>
        <SessionClients>
            <SessionClient>
                <ClientId>BSAC</ClientId>
                <ParticipationCode>Client</ParticipationCode>
            </SessionClient>
        </SessionClients>
        <TimeMinutes>0</TimeMinutes>
        <TotalCost>0</TotalCost>
        <Quantity>1</Quantity>
        <Topic>OTHER</Topic>
    </Session>

    <Session>
        <SessionId>ABC181_1484</SessionId>
        <CaseId>KIBB2</CaseId>
        <SessionDate>2018-01-30</SessionDate>
        <ServiceTypeId>1</ServiceTypeId>
        <TotalNumberOfUnidentifiedClients>0</TotalNumberOfUnidentifiedClients>
        <FeesCharged>0</FeesCharged>
        <MoneyBusinessCommunityEducationWorkshopCode>0</MoneyBusinessCommunityEducationWorkshopCode>
        <InterpreterPresent>0</InterpreterPresent>
        <SessionClients>
            <SessionClient>
                <ClientId>BSAC</ClientId>
                <ParticipationCode>Client</ParticipationCode>
            </SessionClient>
        </SessionClients>
        <TimeMinutes>0</TimeMinutes>
        <TotalCost>0</TotalCost>
        <Quantity>1</Quantity>
        <Topic>OTHER</Topic>

    </Session>
<Sessions/>

0

2 Answers 2

1

The transformation you want to do boils down to changing the order of child elements in each Session element the following way:

  • Copy all elements except TimeMinutes, TotalCost, Quantity, Topic and SessionClients.
  • Then copy the above element in the following order: SessionClients, TimeMinutes, TotalCost, Quantity, and Topic.

So the most natural way is to express this in a template matching Session. Fortunately, XSLT allows XPaths with except clause, so the content of the template is quite close to the above open text wording.

You need also the identity template.

So the whole script can look like below:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

  <xsl:template match="Session">
    <xsl:copy>
      <xsl:apply-templates select="* except (TimeMinutes,
        TotalCost, Quantity, Topic, SessionClients)"/>
      <xsl:apply-templates select="SessionClients, TimeMinutes,
        TotalCost, Quantity, Topic"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
  </xsl:template>
</xsl:transform>
Sign up to request clarification or add additional context in comments.

3 Comments

Note that this is XSLT 2.0.
I have added a transformation as follows & as per guidance thank you, however but it seems to exclude the session element - What I am adding is as follows:
The template matching Session in my solution contains <xsl:copy> at the very start and </xsl:copy> at the very end. So it does copy opening / closing tag of Session element. Check your code whether it includes these instructions. Another way to check: Use an online XSLT verifier (e.g. xsltransform.net). Enter the source XML and my script and you will see the result.
0

I think the simplest (which handles the input being in ANY order, not necessarily the order in your example) is to do

<xsl:template match="Session">
  <xsl:copy-of select="SessionId, CaseId, SessionDate,
 ServiceTypeId, TotalNumberOfUnidentifiedClients,
 FeesCharged,
 MoneyBusinessCommunityEducationWorkshopCode,
 InterpreterPresent, SessionClients, TimeMinutes,
 TotalCost, Quantity, Topic"/>
</xsl:template>

With XSLT 1.0 you can't use the "," operator, you will have to break it out into a sequence of xsl:copy-of instructions like

<xsl:copy-of select="SessionId"/>
<xsl:copy-of select="CaseId"/>
etc.

(Please in future questions say which version of XSLT you are using, it saves everyone time and effort.)

5 Comments

Hi Michael Kay,
Thank You - the copy in XSLT is useful for this.
If it solves the problem please mark the answer as accepted by clicking on the tick/check mark next to the answer
I have added a transformation using xlst 1.0 as recommended as above. The child elements are sorted however I have lost/excluded the 'session' parent element. Would there be anything additional that would need to be added so that each session parent element is still included?
Just wrap all the xsl:copy-of instructions in <Session>...</Session> or <xsl:copy>...</xsl:copy. (This is really elementary...)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.