RE: [xsl] xsl: parsing through specific child nodes

Subject: RE: [xsl] xsl: parsing through specific child nodes
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Tue, 9 Sep 2008 17:21:08 +0100
> Could somebody please help me understand why I am losing indentation.

What processor are you using? The result of indent="yes" is not specified
precisely in the spec, and I seem to recall some processors just give you a
newline and no spaces. Not very friendly, but legal.

Michael Kay
http://www.saxonica.com/

> Below are the complete details.
> 
> On Mon, Sep 8, 2008 at 12:57 PM, Mohit Anchlia 
> <mohitanchlia@xxxxxxxxx> wrote:
> > So I kind of got it working but need some help, I'll first 
> post xml, 
> > xsl and output and then ask my questions:
> >
> > 1. XML
> >
> > <body>
> > <ns2:getMessages xmlns:ns2="http://www.abc.com/wsdl/v";>
> >         <ret>
> >            <Msg>
> >               <cid>103850015_0_1219420995471</cid>
> >               <fid>41</fid>
> >               <filing>IS</filing>
> >               <State>PENDING</State>
> >               <details>
> >                  <Error>
> >                     <Problem>Its pending</Problem>
> >                  </Error>
> >               </details>
> >            </Msg>
> >         </ret>
> > </ns2:getMessages>
> > </body>
> >
> >
> > 2. xsl
> >
> > <?xml version="1.0"?>
> > <xsl:stylesheet 
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0"
> > exclude-result-prefixes="xmlns:ns2 ns2 xmlns"> <xsl:output 
> > method="xml" indent="yes" /> <xsl:variable name="file2" 
> > select="document('EFF')" /> <xsl:key name='PENDING' 
> match='statusMsg' 
> > use='./State'/> <xsl:template match="/">
> >   <xsl:choose>
> >    <xsl:when test="not(//State='PENDING')
> >                and not(//State='SUCCEDED')">
> >       <ret>
> >          <xsl:copy-of select="//ret/*" />
> >       </ret>
> >    </xsl:when>
> >    <xsl:when test="not($file2//State='PENDING')
> >                and not($file2//State='SUCCEDED')">
> >       <ret>
> >          <xsl:copy-of select="$file2//ret/*" />
> >       </ret>
> >    </xsl:when>
> >    <xsl:otherwise>
> >          <xsl:for-each select="//ret/*">
> >             <xsl:apply-templates select="*"/>
> >          </xsl:for-each>
> >    </xsl:otherwise>
> >  </xsl:choose>
> > </xsl:template>
> > <xsl:template match="ret">
> >       <xsl:apply-templates select="*"/> </xsl:template> 
> <xsl:template 
> > match="*">  <xsl:element name="{name()}" 
> > namespace="{namespace-uri()}">
> >   <xsl:choose>
> >     <xsl:when test=".='PENDING'">
> >             <xsl:text>1</xsl:text>
> >     </xsl:when>
> >   <xsl:otherwise>
> >    <xsl:choose>
> >     <xsl:when test="*">
> >       <xsl:apply-templates select="*"/>
> >     </xsl:when>
> >     <xsl:otherwise>
> >        <xsl:value-of select="." />
> >     </xsl:otherwise>
> >    </xsl:choose>
> >   </xsl:otherwise>
> >  </xsl:choose>
> >  </xsl:element>
> > </xsl:template>
> > </xsl:stylesheet>
> >
> > 3. output
> >
> > <?xml version="1.0" encoding="UTF-8"?> 
> > <cid>103850015_0_1219420995471</cid>
> > <fid>41</fid>
> > <filing>IS</filing>
> > <State>1</State>
> > <details>
> > <Error>
> > <Problem>Its pending</Problem>
> > </Error>
> > </details>
> >
> > Questions:
> >
> > 1. But now I don't get <ret> and <Msg> tags, Msg tag in one 
> xml could 
> > be Msg and other it could <CMsg> rest of the tags are same. 
> How can I 
> > get them.
> > 2. Also I am losing the indentation, it's all appearing on first 
> > column. I did get rid of ns2 though.
> > 3. In above xsl what do I have to do if I want to make sure 
> that it's 
> > the element node "State" whose child text node is "PENDING"?
> >
> > Also am I doing this xsl transformation correctly, in the 
> sense that 
> > do you see any problems in terms of how it's done, efficiency etc.
> >
> > Thanks for your help.
> > On Mon, Sep 8, 2008 at 12:31 PM, Michael Kay 
> <mike@xxxxxxxxxxxx> wrote:
> >> When you apply-templates to the ret element it does 
> apply-templates 
> >> on the Msg element, which does xsl:copy-of the Msg 
> element. It does 
> >> not not do an apply-templates on the State element so the 
> code that replaces "PENDING"
> >> with "1" is never activated.
> >>
> >> Michael Kay
> >> http://www.saxonica.com/
> >>
> >>> -----Original Message-----
> >>> From: Mohit Anchlia [mailto:mohitanchlia@xxxxxxxxx]
> >>> Sent: 08 September 2008 18:45
> >>> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> >>> Subject: Re: [xsl] xsl: parsing through specific child nodes
> >>>
> >>> Sorry I gave incorrect xml document:
> >>>
> >>> Here is the correct one:
> >>>
> >>> 1. xml document
> >>>
> >>> <body>
> >>> <ns2:getMessages xmlns:ns2="http://www.abc.com/wsdl/v";>
> >>>          <ret>
> >>>             <Msg>
> >>>                <cid>103850015_0_1219420995471</cid>
> >>>                <fid>41</fid>
> >>>                <filing>IS</filing>
> >>>                <State>PENDING</State>
> >>>             </Msg>
> >>>          </ret>
> >>> </ns2:getMessages>
> >>> </body>
> >>> 2. xsl file:
> >>>
> >>>
> >>> <?xml version="1.0"?>
> >>> <xsl:stylesheet
> >>> xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0"
> >>>
> >>> exclude-result-prefixes="xmlns:ns2 ns2 xmlns">
> >>>
> >>> <xsl:output method="xml" indent="yes" />
> >>>
> >>> <xsl:variable name="file2" select="document('EFF')" /> <xsl:key 
> >>> name='PENDING' match='Msg' use='./State'/> <xsl:template 
> match="/">
> >>>   <xsl:choose>
> >>>    <xsl:when test="not(//State='PENDING')
> >>>                and not(//State='SUCCEDED')">
> >>>       <ret>
> >>>          <xsl:copy-of select="//ret/*" />
> >>>       </ret>
> >>>    </xsl:when>
> >>>    <xsl:when test="not($file2//State='PENDING')
> >>>                and not($file2//State='SUCCEDED')">
> >>>       <ret>
> >>>          <xsl:copy-of select="$file2//ret/*" />
> >>>       </ret>
> >>>    </xsl:when>
> >>>    <xsl:otherwise>
> >>>          <xsl:apply-templates select="//ret"/>
> >>>    </xsl:otherwise>
> >>>  </xsl:choose>
> >>> </xsl:template>
> >>> <xsl:template match="ret">
> >>>       <xsl:apply-templates select="*"/>
> >>>
> >>> </xsl:template>
> >>> <xsl:template match="*">
> >>>
> >>>  <xsl:copy>
> >>>   <xsl:choose>
> >>>     <xsl:when test="text()='PENDING'">
> >>>             <xsl:text>1</xsl:text>
> >>>     </xsl:when>
> >>>   <xsl:otherwise>
> >>>     <xsl:copy-of select="." />
> >>>
> >>>   </xsl:otherwise>
> >>>  </xsl:choose>
> >>>  </xsl:copy>
> >>>
> >>> </xsl:template>
> >>> </xsl:stylesheet>
> >>>
> >>> 3. Output:
> >>>
> >>> <?xml version="1.0" encoding="UTF-8"?>
> >>>
> >>> <Msg xmlns:ns2="http://www.abc.com/wsdl/v";>
> >>> <Msg>
> >>>               <cid>103850015_0_1219420995471</cid>
> >>>               <fid>41</fid>
> >>>               <filing>IS</filing>
> >>>               <State>PENDING</State>
> >>>            </Msg>
> >>> </Msg>
> >>>
> >>>
> >>> On Mon, Sep 8, 2008 at 10:03 AM, Michael Kay <mike@xxxxxxxxxxxx> 
> >>> wrote:
> >>> > In your match="/" template, the only apply-templates is to
> >>> an element
> >>> > called "ret". There is no element named ret in your source
> >>> document.
> >>> > Therefore the template rule with match="*" will never fire,
> >>> therefore
> >>> > the code that replaces "PENDING" by "1" will not be executed.
> >>> >
> >>> > Michael Kay
> >>> > http://www.saxonica.com/
> >>> >
> >>> >> -----Original Message-----
> >>> >> From: Mohit Anchlia [mailto:mohitanchlia@xxxxxxxxx]
> >>> >> Sent: 08 September 2008 17:48
> >>> >> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> >>> >> Subject: Re: [xsl] xsl: parsing through specific child nodes
> >>> >>
> >>> >> So I tried various things but it doesn't seem to be working.
> >>> >> I'll give the complete information:
> >>> >>
> >>> >> 1. xml file:
> >>> >> <?xml version="1.0" encoding="UTF-8"?> <Msg 
> >>> >> xmlns:ns2="http://www.abc.com/wsdl/v";>
> >>> >> <Msg>
> >>> >>                <cid>103850015_0_1219420995471</cid>
> >>> >>                <fid>41</fid>
> >>> >>                <filing>IS</filing>
> >>> >>                <State>PENDING</State>
> >>> >>             </Msg>
> >>> >> </Msg>
> >>> >>
> >>> >> 2. xsl file:
> >>> >>
> >>> >> <?xml version="1.0"?>
> >>> >> <xsl:stylesheet
> >>> >> xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0"
> >>> >> exclude-result-prefixes="xmlns:ns2 ns2 xmlns"> <xsl:output 
> >>> >> method="xml" indent="yes" /> <xsl:variable name="file2"
> >>> >> select="document('EFF')" /> <xsl:key name='PENDING'
> >>> >> match='Msg' use='./State'/> <xsl:template match="/">
> >>> >>    <xsl:choose>
> >>> >>     <xsl:when test="not(//State='PENDING')
> >>> >>                 and not(//State='SUCCEDED')">
> >>> >>        <ret>
> >>> >>           <xsl:copy-of select="//ret/*" />
> >>> >>        </ret>
> >>> >>     </xsl:when>
> >>> >>     <xsl:when test="not($file2//State='PENDING')
> >>> >>                 and not($file2//State='SUCCEDED')">
> >>> >>        <ret>
> >>> >>           <xsl:copy-of select="$file2//ret/*" />
> >>> >>        </ret>
> >>> >>     </xsl:when>
> >>> >>     <xsl:otherwise>
> >>> >>           <xsl:apply-templates select="//ret"/>
> >>> >>     </xsl:otherwise>
> >>> >>   </xsl:choose>
> >>> >> </xsl:template>
> >>> >> <xsl:template match="ret">
> >>> >>        <xsl:apply-templates select="*"/> </xsl:template> 
> >>> >> <xsl:template match="*">  <xsl:copy>
> >>> >>    <xsl:choose>
> >>> >>      <xsl:when test="text()='PENDING'">
> >>> >>              <xsl:text>1</xsl:text>
> >>> >>      </xsl:when>
> >>> >>    <xsl:otherwise>
> >>> >>      <xsl:copy-of select="." />
> >>> >>    </xsl:otherwise>
> >>> >>   </xsl:choose>
> >>> >>  </xsl:copy>
> >>> >> </xsl:template>
> >>> >> </xsl:stylesheet>
> >>> >>
> >>> >> 3. Output:
> >>> >> <?xml version="1.0" encoding="UTF-8"?> <Msg 
> >>> >> xmlns:ns2="http://www.abc.com/wsdl/v";>
> >>> >> <Msg>
> >>> >>                <cid>103850015_0_1219420995471</cid>
> >>> >>                <fid>41</fid>
> >>> >>                <filing>IS</filing>
> >>> >>                <State>PENDING</State>
> >>> >>             </Msg>
> >>> >> </Msg>
> >>> >>
> >>> >> 4.expected output:
> >>> >>
> >>> >> <?xml version="1.0" encoding="UTF-8"?> <Msg>
> >>> >>                <cid>103850015_0_1219420995471</cid>
> >>> >>                <fid>41</fid>
> >>> >>                <filing>IS</filing>
> >>> >>                <State>1</State>
> >>> >>             </Msg>
> >>> >> </Msg>
> >>> >>
> >>> >>
> >>> >> First I don't understand how there are 2 Msg nodes. 
> And second I 
> >>> >> wasn't able to get rid of namespace node by using <element> as 
> >>> >> suggested by Michael, it's still copying the namespace node.
> >>> >> On Mon, Sep 8, 2008 at 6:52 AM, Mukul Gandhi 
> >>> >> <gandhi.mukul@xxxxxxxxx> wrote:
> >>> >> > On Mon, Sep 8, 2008 at 1:16 AM, Mohit Anchlia
> >>> >> <mohitanchlia@xxxxxxxxx> wrote:
> >>> >> >> 1. So would above template mentioned by Mukul also output
> >>> >> node HIJ ?
> >>> >> >
> >>> >> > I think, "outputting the node" is not the correct
> >>> >> terminology. We can
> >>> >> > copy the node to the result tree, or write something else to 
> >>> >> > the result tree, derived from the properties of the 
> input nodes.
> >>> >> >
> >>> >> >>       <xsl:when test="local-name()="HIJ" and . = 'YYYYYY'">
> >>> >> >
> >>> >> > This statement will probably not compile, as I can see some
> >>> >> misplaced quotes.
> >>> >> >
> >>> >> >
> >>> >> >> 3. Currently I am using XSLT 1.0 and I am using JAXP which
> >>> >> uses Xalan.
> >>> >> >> How do I start using XSLT 2.0.
> >>> >> >
> >>> >> > You need to download an XSLT 2.0 processor, like Saxon and
> >>> >> using it as
> >>> >> > described in the documentation.
> >>> >> >
> >>> >> >> Would it just be matter of upping version in 
> stylesheet node?
> >>> >> >
> >>> >> > No. version="2.0" is just a hint to the processor. You need
> >>> >> to supply
> >>> >> > the XSLT 2.0 stylesheet to a XSLT 2.0 processor like Saxon.
> >>> >> >
> >>> >> >
> >>> >> > --
> >>> >> > Regards,
> >>> >> > Mukul Gandhi

Current Thread