0

I have the following structure of xml data to transform:

     <chapter>
          <title>Text</title>
          <subtitle>Text</subtitle>
          <paragraph>Text</paragraph>
          <paragraph>Text</paragraph>
          <subtitle>Text</subtitle>
          <paragraph>Text</paragraph>
          <other>Text</other>
      </chapter>

      <chapter>
          <title>Text</title>
          <paragraph>Text</paragraph>
          <paragraph>Text</paragraph>
          <paragraph>Text</paragraph>
          <other>Text</other>
      </chapter>

      <chapter>
          <title>Text</title>
          <paragraph>Text</paragraph>
          <subtitle>Text</subtitle>
          <paragraph>Text</paragraph>
          <paragraph>Text</paragraph>
          <other>Text</other>
      </chapter>

As you can see, the subtitles in the different chapters have no permanent pattern. In the output, I need to set the subtitles on the same place like the are in the xml. For the paragraph tags, I use a for-each loop. Like this:

<xsl:template match="chapter">
  <xsl:for-each select="paragraph">
    <xsl:value-of select="."/>
  </xsl:for-each>
</xsl:template>

And now, I need to set the subtitles above, between or among the paragraphs in the order they are in the xml. How can I do this? Please help!

1
  • What does your expected output look like? You haven't told us yet. Commented Jan 22, 2013 at 17:05

2 Answers 2

1

By using

 <xsl:for-each select="paragraph">

You are pulling all the paragraph elements out first, You could change that to

<xsl:for-each select="*">

To process all elements in order, but it is better (or at least more idiomatic xslt) to avoid for-each and use apply-templates instead.

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


<xsl:template match="title">
Title: <xsl:value-of select="."/>
</xsl:template>


<xsl:template match="subtitle">
SubTitle: <xsl:value-of select="."/>
</xsl:template>


<xsl:template match="paragraph">
 <xsl:text>&#10;&#10;</xsl:text>
 <xsl:value-of select="."/>
<xsl:text>&#10;&#10;</xsl:text>
</xsl:template>
Sign up to request clarification or add additional context in comments.

Comments

0

Would this do it?

<xsl:template match="chapter">
  <xsl:for-each select="paragraph | subtitle">
    <xsl:value-of select="."/>
  </xsl:for-each>
</xsl:template>

But as David Carlisle points out, the typical XSLT approach is to split this out into templates, and this especially makes sense if you want special handling for certain ones:

<xsl:template match="chapter">
   <xsl:apply-templates select="paragraph | subtitle" />
</xsl:template>

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

<xsl:template match="subtitle">
   <!-- do stuff with subtitles -->
</xsl:template>

2 Comments

Yes, thank you, it solved a partial problem and I found the solution for the other. I combine your suggestion with an <xsl:if test="name(.) = 'subtitle'">Do stuff with subtitles</xsl:if> to have the possibility to do different things with them both.
Great. Though if your subtitles need special handling, it would be more ideal to split the logic up into separate templates as David Carlisle suggested. I've included a sample above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.