1
votes

I'm currently trying to convert a section of a very messy xml to something more readable, but when my code isn't producing what I want.

Could I get some feedback on what's wrong with my code, and how I can fix it?

Example input:

<root>
 <body>
   <para>
    <heading> name </heading>
   </para>
   <para> This is the name </para>
   <para>
    <heading> Usage </heading>
   </para>
   <para> This is the usage </para>
 </body>
<root>

The output I'd like to see is:

<root>
 <conbody>
  <section>
   <title> Name </title>
   <p> This is the name </p>
  </section>
  <section>
   <title> Usage </title>
   <p> This is the usage </p>
 <conbody>
<root>

My code currently looks like this:

<xsl:template match="body">
    <conbody>
        <xsl:for-each-group select="para" group-starting-with="para[heading]">
            <section>
                <title>
                    <xsl:apply-templates select="element()"/>
                </title>
                <p>
                    <xsl:apply-templates select="*"/>
                </p>
            </section>
        </xsl:for-each-group>
    </conbody>
</xsl:template>

The content is not being copied correctly, and I'm not sure why?

1
Try current-group()[1] in the first xsl:apply-templates and current-group()[not(position()=1)] in the second xsl:apply-templates.Daniel Haley
I end up getting something like: <section> <title> <para> Name </para> </title> <p> <para> This is the name </para> </p> </section>RyRong
Sorry, i'm not sure how to indent properly in a comment.RyRong
Sounds like you just need templates to handle para in/out of title. The grouping looks right; unless I'm missing something?Daniel Haley
You're right, I'll go write the template right now. Thank you!RyRong

1 Answers

2
votes

It's because you need to apply-templates to the current-group().

You could try using current-group()[1] in the first xsl:apply-templates and current-group()[not(position()=1)] in the second xsl:apply-templates; this should get you close.

Here's an example of a slightly different approach to creating the title and p elements...

XML Input

<root>
    <body>
        <para>
            <heading> name </heading>
        </para>
        <para> This is the name </para>
        <para>
            <heading> Usage </heading>
        </para>
        <para> This is the usage </para>
    </body>
</root>

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template> 

  <xsl:template match="body">
    <conbody>
      <xsl:for-each-group select="para" group-starting-with="para[heading]">
        <section>
          <xsl:apply-templates select="current-group()"/>
        </section>
      </xsl:for-each-group>
    </conbody>
  </xsl:template>

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

  <xsl:template match="para/text()">
    <p><xsl:value-of select="."/></p>
  </xsl:template>

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

</xsl:stylesheet>

XML Output

<root>
   <conbody>
      <section>
         <title> name </title>
         <p> This is the name </p>
      </section>
      <section>
         <title> Usage </title>
         <p> This is the usage </p>
      </section>
   </conbody>
</root>