0

I'm trying to parse an XML document with XSLT, but I'm really newbie with this.

I already generated an XML document like this:

<DOC>
<FORM>VI0CBCNE</FORM>
<DAY>23</DAY>
<FORM>AP0002</FORM>
<BAR>109130000005</BAR>
<CODBAR>109130000005</CODBAR>
<FORM>AP0001</FORM>
</DOC>

And I want to transform it into something like this:

<DOC>
  <DOC_FORM>
    <FORM>VI0CBCNE</FORM>
    <DAY>23</DAY>
  </DOC_FORM>
  <DOC_FORM>
    <FORM>AP0002</FORM>
    <BAR>109130000005</BAR>
    <CODBAR>109130000005</CODBAR>
  </DOC_FORM>
  <DOC_FORM>
    <FORM>AP0001</FORM>
  </DOC_FORM>
</DOC>

The number of FORM nodes could change, also the number of nodes between FORMS.

I'm not even close of the solution, so I can't share my XSL. Could someone help me with at least a clue with what I can do? I'm using apache camel and an XSLT 2.0 processor.

emoyano
  • 3
  • 1

2 Answers2

0

The following XSLT will produce your result. Limitation. Only defined nodes will be mapped and in the order specified in the XSLT rather than the order of the source.

<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" version="1.0">
  <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
  <xsl:template match="/">
    <xsl:apply-templates select="/DOC" />
  </xsl:template>
  <xsl:template match="/DOC">
    <DOC>
      <xsl:for-each select="FORM">
        <xsl:variable name="pos" select="position()" />
        <DOC_FORM>
          <FORM>
            <xsl:value-of select="./text()" />
          </FORM>
          <xsl:if test="//BAR[$pos = count(preceding-sibling::FORM)]">
            <BAR>
              <xsl:value-of select="//BAR[$pos = count(preceding-sibling::FORM)]/text()" />
            </BAR>
          </xsl:if>
          <xsl:if test="//CODBAR[$pos = count(preceding-sibling::FORM)]">
            <CODBAR>
              <xsl:value-of select="../CODBAR[$pos = count(preceding-sibling::FORM)]/text()" />
            </CODBAR>
          </xsl:if>
          <xsl:if test="//DAY[$pos = count(preceding-sibling::FORM)]">
            <DAY>
              <xsl:value-of select="../DAY[$pos = count(preceding-sibling::FORM)]/text()" />
            </DAY>
          </xsl:if>
        </DOC_FORM>
      </xsl:for-each>
    </DOC>
  </xsl:template>
</xsl:stylesheet>
Dijkgraaf
  • 11,049
  • 17
  • 42
  • 54
0

Since you are using XSL 2.0, you can take advantage of the xsl:for-each-group element, with its group-starting-with option:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/DOC">
    <xsl:copy>
        <xsl:for-each-group select="*" group-starting-with="FORM">
            <DOC_FORM>
                <xsl:copy-of select="current-group()" />
            </DOC_FORM>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51