tags:

views:

33

answers:

2

I have an xml

<Root>
  <Parent>
    <Child1>A</Child1>
    <Child2>B</Child2>
    <Child1>X</Child1>
    <Child2>Y</Child2>
  </Parent>
</Root>

Child2 always will be with child1. I need to know how I can loop through using xsl:foreach and create an XML output example.

<TransformedXML>
  <Child attribute1="A" attribute2="B"/>
  <Child attribute1="X" attribute2="Y"/>
</TransformedXML>

My question is how do I loop in XSLT considering Child2 node will follow a Child1 always?

+1  A: 

This transformation:

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

 <xsl:key name="kFollowingChild1" match="*[not(self::Child1)]"
  use="generate-id(preceding-sibling::Child1[1])"/>

 <xsl:template match="Parent">
  <TransformedXML>
   <xsl:apply-templates/>
  </TransformedXML>
 </xsl:template>

 <xsl:template match="Child1">
  <Child>
   <xsl:for-each select=".|key('kFollowingChild1', generate-id())">
    <xsl:attribute name="attribute{position()}">
      <xsl:value-of select="."/>
    </xsl:attribute>
   </xsl:for-each>
  </Child>
 </xsl:template>

 <xsl:template match="text()"/>
</xsl:stylesheet>

when applied on the provided (corrected many times to become well-formed!) XML document:

<Root>
    <Parent>
        <Child1>A</Child1>
        <Child2>B</Child2>
        <Child1>X</Child1>
        <Child2>Y</Child2>
    </Parent>
</Root>

produces the wanted, correct result:

<TransformedXML>
   <Child attribute1="A" attribute2="B"/>
   <Child attribute1="X" attribute2="Y"/>
</TransformedXML>
Dimitre Novatchev
Thanks. Also What if myChild is <Root> <Parent> <Child1><Small>1</small></Child1> <Child2>B</Child2> <Child1>X</Child1> <Child2>Y</Child2> </Parent></Root>How can I loop thru the Child1 to get small with the above XSLT. I am confused why I am getting the inner Text.
Greens
@Greens: I don't understand -- please, describe better. What do you want to get as result (XML, please)?
Dimitre Novatchev
INPUT<Root> <Parent> <Child1><Small>1</small></Child1> <Child2>B</Child2> <Child1>X</Child1> <Child2>Y</Child2> </Parent> </Root>------------------------------------OUTPUT<TransformedXML> <Child attribute1="A" anyName="1" attribute2="B"/> <Child attribute1="X" attribute2="Y"/></TransformedXML>
Greens
This is significantly different than what you're asking in your question. Please, ask a new question with your new requirements. Think well before posting the new question, or you may miss something important again. For example, it is not clear in your new desired output, what `anyName` should mean and how it is related to the source XML.
Dimitre Novatchev
A: 

Is there a specific reason why you wan't to use xsl:for-each? I'd suggest to just use matching templates:

<xsl:template match="Child1">
  <Child attribute1="{.}" attribute2="{following-sibling::*[1]}"/>
</xsl:template>

<xsl:template match="Child2"/>

This will work just fine as long as the prerequisite that Child1 always will be the first following sibling of Child2.

Per T