tags:

views:

69

answers:

2

Hello,

The best way to explain my problem is to give an example xml:

<block>
  <if>
    <trans>
      <trans1>
        <text1>text</text1>
      </trans1>
      <trans1>
        <text1>text</text1>
      </trans1>
    </trans>
    <if>
      <trans>
        .......
      </trans>
    </if>
  </if>
</block>

So to capture all the data in it, you would do a (xsl: for-each select = "block/if/trans/trans1")... get the data. Now I want to move out of trans and trans1 so I can go into "block/if/if"...

I know I could do a seperate for-each but I need to get all of this data in one cell in a table so you would need to do a nested for-each but I don't know if you can/ if it is possible to move back a bit?

Does anyone know if this is possible and if so how to do it?

Thanks.

A: 

Its not entirely clear what you need to do. Here is my guess you want to retrieve from /block/if all trans/trans1 elements regardless of which if they are found under. On that basis try:-

 <xsl:for-each select="block/if//trans/trans1">

Note the // in the path is shorthand for descendants:: and will select any occurance of trans at any depth below the parent if.

AnthonyWJones
+1  A: 

So to capture all the data in it, you would do a (xsl: for-each select = "block/if/trans/trans1")

No I wouldn't. I almost never use for-each. I'd do:

<xsl:apply-templates select="block/if/trans/trans1"/>

Now I want to move out of trans and trans1 so I can go into "block/if/if"..

If trans1 is the context node, you can use the ancestor axis to get to its first if ancestor:

<xsl:template match="trans1">
   <xsl:apply-templates select="ancestor::if[1]"/>
</xsl:template>

It's really not clear what you're asking, though. Are you trying to flatten out the hierarchy, and create an HTML table from each block that has a tr for each if, and a td for each text1 element beneath each if? If so, that would require something like this:

<xsl:template match="block">
   <table>
      <xsl:apply-templates select=".//if"/>
   </table>
</xsl:template>

<xsl:template match="if">
   <tr>
      <xsl:apply-templates select="trans/trans1/text1"/>
   </tr>
</xsl:template>

<xsl:template match="text1">
   <td>
      <xsl:value-of select="."/>
   </td>
</xsl:template>

In the example above, I've assumed that you know the exact path to the text1 descendant, as shown in your example.

If you don't know the exact path from the if element to the text1 descendants, it's trickier. You don't want to use

.//text1

because that will select all text1 descendants, including the ones that are descendants of the descendant if elements. That would result in the same text1 element producing multiple td elements in the output - one for each if element it's a descendant of. To avoid this, you need to use a pattern like:

text1 | .//*[name() != 'if']//text1

This selects any immediate text1 children, and also any text1 descendants that are not themselves descendants of descendant if elements.

Actually, this would also work:

.//text1[ancestor::if[1] = current()]

That finds all text1 descendants whose first if ancestor, moving up the chain of ancestors, is the current if element. This is easier to understand than the first example, but the first example probably performs better, unless the XSLT processor is really smart.

Robert Rossney