Question

<Root>
  <Envelope>
    <Header>
      <ineed>apple</ineed>
    </Header>
    <success></success>
  </Envelope>
  <Envelope>
    <Header>
      <ineed>apple</ineed>
    </Header>
    <success></success>
  </Envelope>


  <Envelope>
    <Header>
      <ineed>apple</ineed>
    </Header>
    <criticalerror></criticalerror>
  </Envelope>
  <Envelope>
    <Header>
      <ineed>apple</ineed>
    </Header>
    <success></success>
  </Envelope>


  <Envelope>
    <Header>
      <ineed>apple</ineed>
    </Header>
    <criticalerror></criticalerror>
  </Envelope>
  <Envelope>
    <Header>
      <ineed>apple</ineed>
    </Header>
    <criticalerror></criticalerror>
  </Envelope>


  <Envelope>
    <Header>
      <ineed>apple</ineed>
    </Header>
    <milderror></milderror>
  </Envelope>
  <Envelope>
    <Header>
      <ineed>apple</ineed>
    </Header>
    <success></success>
  </Envelope>
</Root>

Hi,

I am not sure how to get this working with xslt. The xml file has "Envelope" elements always in even number of occurences, the reason being, the xml will indicate us success, error or warning based on pairs(first and second, third and fourth etc). The top priority is for "criticalerror" element, that is, if this element is present in the pair, the pair is considered as error, the element can occur twice as well.

The next priority goes to "milderror" element which stands for warning. The third priority goes to "success" element. Therefore only if both contains "success" in the pair, considered as success.

For the above case first pair is success, second one is an error, third one is an error, fourth one is a warning. There are two errors, one success and one warning. This will produce an xml like below. Again, error is having higher priority(occurs first in xml), warning next

<Root>
  <error></error>
  <error></error>
  <warning></warning>
  <success></success>
</Root>

Now I have a for each action with the above xml, for each paired scenarios(success, error and warning), there are three for each actions(that is how my design is ), which is an action in datapower

Coming to my success for each action, I need to get the "ineed" element from the top xml, corresponding to the success pair, which is "apple", this can occur in either one or both, within a pair of top xml. It is same for a pair, however can occur in either one, or both.

All I have is the context loopcount variable(1 in this case), for success, which is going to iterate for all success scenario

Similary for error scenario(looping 2 times in this case), need to get the corresponding "ineed" element from top xml. Loopcount variable 1, next time loopcount variable is 2

Samething for warning scenario as well.

Was it helpful?

Solution

Here is a complete solution:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/*">
     <Root>
      <xsl:apply-templates select="Envelope[position() mod 2 = 1]">
       <xsl:sort select=
         "not((.|following-sibling::Envelope[1])/criticalerror)"/>
       <xsl:sort select=
         "not((.|following-sibling::Envelope[1])/milderror)"/>
      </xsl:apply-templates>
     </Root>
 </xsl:template>

 <xsl:template match=
  "Envelope
    [position() mod 2 = 1
   and
     success
   and
     following-sibling::Envelope[1]/success
    ]">

  <success>
   <xsl:call-template name="getTitle"/>
  </success>
 </xsl:template>

 <xsl:template match=
  "Envelope
    [position() mod 2 = 1
   and
     (.|following-sibling::Envelope[1])/criticalerror
    ]">

  <error>
   <xsl:call-template name="getTitle"/>
  </error>
 </xsl:template>

 <xsl:template match=
  "Envelope
    [position() mod 2 = 1
   and
     (.|following-sibling::Envelope[1])/milderror
   and
     not((.|following-sibling::Envelope[1])/criticalerror)
    ]">

  <warning>
   <xsl:call-template name="getTitle"/>
  </warning>
 </xsl:template>

 <xsl:template name="getTitle">
  <xsl:value-of select=
    "(.|following-sibling::Envelope[1])
         /Header/ineed[normalize-space()]
                                       [1]
    "/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

when this transformation is applied on the provided XML document:

<Root>
    <Envelope>
        <Header>
            <ineed>apple</ineed>
        </Header>
        <success></success>
    </Envelope>
    <Envelope>
        <Header>
            <ineed>apple</ineed>
        </Header>
        <success></success>
    </Envelope>
    <Envelope>
        <Header>
            <ineed>apple</ineed>
        </Header>
        <criticalerror></criticalerror>
    </Envelope>
    <Envelope>
        <Header>
            <ineed>apple</ineed>
        </Header>
        <success></success>
    </Envelope>
    <Envelope>
        <Header>
            <ineed>apple</ineed>
        </Header>
        <criticalerror></criticalerror>
    </Envelope>
    <Envelope>
        <Header>
            <ineed>apple</ineed>
        </Header>
        <criticalerror></criticalerror>
    </Envelope>
    <Envelope>
        <Header>
            <ineed>apple</ineed>
        </Header>
        <milderror></milderror>
    </Envelope>
    <Envelope>
        <Header>
            <ineed>apple</ineed>
        </Header>
        <success></success>
    </Envelope>
</Root>

the wanted, correct result is produced:

<Root>
   <error>apple</error>
   <error>apple</error>
   <warning>apple</warning>
   <success>apple</success>
</Root>

Explanation:

  1. No <xsl:for-each> is used, only <xsl:apply-templates>.

  2. Templates are explicitly applied only on the first Envelope of each pair of Envelope elements.

  3. The order in which the result of processing the elements (in the node-list specified in the select attribute of xsl:apply-templates) is output, is specified in two xsl:sort instructions -- first go errors, then warnings, then anything else (success).

  4. We use the fact that when booleans are sorted, false() precedes true().

  5. The template named getTitle is called to output the wanted string value of the first non-empty ineed element contained in the respective pair of Envelope elements.

OTHER TIPS

Why are you using a for-each? You don't need a loop counter, as far as I can tell. You want to select the first elements in each pair (I don't like this design, but let's let that go) like this:

Then write a template for those elements. Within that template, you can get the second element of the pair with the XPath expression "following-sibling::Envelope[1]".

If you need to sort the odd elements, you might want to do something like this:

And so on.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top