Re: [xsl] [xslt] enhance match condition for next node referance

Subject: Re: [xsl] [xslt] enhance match condition for next node referance
From: Ronan Klyne <ronan.klyne@xxxxxxxxxxx>
Date: Thu, 19 Mar 2009 15:21:00 +0000
Michalmas wrote:
> Hi,
> 
> And what about problem when next node (after the interesting node)
> must satisfy some condition? Let's say that node after interestingNode
> must be exit (and only this node can be there). And all nodes are
> encapsulated in one more, like shown below:
> <encapsulating>
>      <interestingNode>
>              <con>someString</con>
>              <follow>
>                      <node1>1</node1>
>                      <test>2</test> <!-- HERE we have required node -->
>                      <node3>3</node3>
>                      <node4>4</node4>
>              </follow>
>              <space>5</space>
>      </interestingNode>
>      <exit /> <!-- HERE the condition -->
> </encapsulating>

The XPath "interestingNode[follow/test and con='someString']" will match
any interestingNode element with a test element inside a follow child,
and the correct text in it's "con" child.

If the node after must be an 'exit' node, then this would be specified
as "following-sibling::node()[1][self::exit]". The "[1]" is important -
it ensures that we are looking at the first following sibling, then in
the condition, we check that this node is an 'exit' node.
"following-sibling::exit" is the wrong way to do it, but I point it out
because it looks OK - this would look at all following siblings (not
just the immediate one) and give you all the ones that were 'exit' elements.

Putting this all together, we get:
"interestingNode[following-sibling::node()[1][self::exit] and
follow/test and con='someString']"

Enjoy,

	Ronan

> On Thu, Mar 19, 2009 at 3:27 PM, Ronan Klyne <ronan.klyne@xxxxxxxxxxx> wrote:
>> Michalmas wrote:
>>> Hi,
>>>
>>> one more question - how to enhance the condition in template to check
>>> if among the children nodes there is <test> node. So, it should work
>>> for:
>>>
>>> <interestingNode>
>>>             <con>someString</con>
>>>             <follow>
>>>                     <node1>1</node1>
>>>                     <test>2</test> <!-- HERE we have required node -->
>>>                     <node3>3</node3>
>>>                     <node4>4</node4>
>>>             </follow>
>>>             <space>5</space>
>>>     </interestingNode>
>>>
>>> but not for:
>>>
>>> <interestingNode>
>>>             <con>someString</con>
>>>             <follow>
>>>                     <node1>1</node1>
>>>                     <node2>2</node2>
>>>                     <node3>3</node3>
>>>                     <node4>4</node4>
>>>             </follow>
>>>             <space>5</space>
>>>     </interestingNode>
>> Change "interestingNode[con='someString']"
>> to "interestingNode[follow/test and con='someString']"
>>
>>> thanks!
>>>
>>> On Thu, Mar 19, 2009 at 10:20 AM, Ronan Klyne <ronan.klyne@xxxxxxxxxxx> wrote:
>>>> Michalmas wrote:
>>>>> Hi guys,
>>>>>
>>>>> I made small error in the example XMLs, actually the main problem i
>>>>> had i skipped.
>>>>>
>>>>> In the result XML, i need to get referance of attribute space of
>>>>> previous node (something like preceding-sibling). If the previous node
>>>>> doens't have it, i need to go further back until i find it or until
>>>>> the beginning of XML.
>>>>>
>>>>> Correct result XML would be:
>>>>> <example>
>>>>>   <someNode>
>>>>>           <value>asas</value>
>>>>>           <name>asas</name>
>>>>>           <space>12</space>
>>>>>   </someNode>
>>>>>   <interestingNode>
>>>>>           <con>someString</con>
>>>>>           <follow>
>>>>>                   <return>0</return>
>>>>>           </follow>
>>>>>           <space>5</space>
>>>>>   </interestingNode>
>>>>>
>>>>>   <node1 space="12">1</node1> <!-- HERE space attribute  -->
>>>>>   <node2 space="12">2</node2>
>>>>>   <node3 space="12">3</node3>
>>>>>   <node4 space="12">4</node4>
>>>>> </example>
>>>> The key difference here will be to use the xpath
>>>> 'preceding-sibling::*[space]/space[1]' to pick the right space tag. The
>>>> logic here is as follows:
>>>> 1) 'preceding-sibling::*' - get all preceding siblings of the current node
>>>> 2) '[space]' - filter these to the ones with a 'space' child.
>>>> 3) '/space[1]' - get the first 'space' child.
>>>>
>>>> <xsl:stylesheet version="1.0"
>>>> xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
>>>>
>>>> <xsl:template match="example">
>>>>  <xsl:apply-templates/>
>>>> </xsl:template>
>>>>
>>>> <xsl:template match="interestingNode[con='someString']">
>>>>  <interestingNode>
>>>>    <xsl:copy-of select="con" />
>>>>    <follow>
>>>>      <return>0</return>
>>>>    </follow>
>>>>    <xsl:copy-of select="space" />
>>>>  </interestingNode>
>>>>  <xsl:variable name="space"
>>>> select="preceding-sibling::*[space]/space[1]" />
>>>>  <xsl:for-each select="follow/*">
>>>>    <xsl:copy>
>>>>      <xsl:attribute name="space" select="$space" />
>>>>      <xsl:copy-of select="node()" />
>>>>    </xsl:copy>
>>>>  </xsl:for-each>
>>>> </xsl:template>
>>>>
>>>> <xsl:template match="*">
>>>>  <xsl:copy-of select="." />
>>>> </xsl:template>
>>>>
>>>> </xsl:stylesheet>
>>>>
>>>>
>>>>
>>>>> On Thu, Mar 19, 2009 at 10:00 AM, Michael Kay <mike@xxxxxxxxxxxx> wrote:
>>>>>> Not the most imaginative title for a post.
>>>>>>
>>>>>>> <example>
>>>>>>>     <someNode>
>>>>>>>             <value>asas</value>
>>>>>>>             <name>asas</name>
>>>>>>>             <space>12</space>
>>>>>>>     </someNode>
>>>>>>>     <interestingNode>
>>>>>>>             <con>someString</con>
>>>>>>>             <follow>
>>>>>>>                     <node1>1</node1>
>>>>>>>                     <node2>2</node2>
>>>>>>>                     <node3>3</node3>
>>>>>>>                     <node4>4</node4>
>>>>>>>             </follow>
>>>>>>>             <space>5</space>
>>>>>>>     </interestingNode>
>>>>>>> </example>
>>>>>>>
>>>>>>>
>>>>>>> Now i want to transform it to:
>>>>>>>
>>>>>>> <example>
>>>>>>>     <someNode>
>>>>>>>             <value>asas</value>
>>>>>>>             <name>asas</name>
>>>>>>>             <space>12</space>
>>>>>>>     </someNode>
>>>>>>>     <interestingNode>
>>>>>>>             <con>someString</con>
>>>>>>>             <follow>
>>>>>>>                     <return>0</return>
>>>>>>>             </follow>
>>>>>>>             <space>5</space>
>>>>>>>     </interestingNode>
>>>>>>>
>>>>>>>     <node1 space="5">1</node1>
>>>>>>>     <node2 space="5">2</node2>
>>>>>>>     <node3 space="5">3</node3>
>>>>>>>     <node4 space="5">4</node4>
>>>>>>> </example>
>>>>>>>
>>>>>>>
>>>>>>> The changes are:
>>>>>>> - when interestingNode is found, we check the con value
>>>>>>> - if con value conforms someString, then we make
>>>>>>> transformation of this part by:
>>>>>>>     - evrything in follow node is moved outside interestingNode
>>>>>>>     - follow node gets one child return
>>>>>>>     - all nodes moved outside get an attribute space with
>>>>>>> value specified in original node
>>>>>>>
>>>>>> That seems to be a rule you can translate directly into XSLT:
>>>>>>
>>>>>> <xsl:template match="interestingNode[con='someString']">
>>>>>>  <xsl:copy>
>>>>>>    <xsl:copy-of select="con"/>
>>>>>>    <follow><return>0</return></follow>
>>>>>>    <xsl:copy-of select="space"/>
>>>>>>  </xsl:copy>
>>>>>>  <xsl:variable name="space" select="space"/>
>>>>>>  <xsl:for-each select="follow/*">
>>>>>>    <xsl:copy>
>>>>>>      <xsl:attribute name="space" select="$space"/>
>>>>>>      <xsl:copy-of select="child::node()"/>
>>>>>>    </xsl:copy>
>>>>>>  </xsl:for-each>
>>>>>> </xsl:template>
>>>>>>
>>>>>> Michael Kay
>>>>>> http://www.saxonica.com/
>>>>>
>>>>>
>>>> --
>>>> Ronan Klyne
>>>> Business Collaborator Developer
>>>> Tel: +44 01189 028518
>>>> ronan.klyne@xxxxxxxxxxx
>>>> www.groupbc.com
>>>
>>>
>>
>> --
>> Ronan Klyne
>> Business Collaborator Developer
>> Tel: +44 01189 028518
>> ronan.klyne@xxxxxxxxxxx
>> www.groupbc.com
> 
> 


-- 
Ronan Klyne
Business Collaborator Developer
Tel: +44 01189 028518
ronan.klyne@xxxxxxxxxxx
www.groupbc.com

Current Thread