0
votes

I need help with some XSLT...

I have the following XML input document:

<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://jasperreports.sourceforge.net/jasperreports" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" 
        repName="FirstElementTemp" 
        date="10-05-2001">
    <element1>
        <![CDATA[]]>
    </element1>
    <element2 name="secondElement"/>
    <head>
        <hText x="10" y="20">
            <textVal>TEXT 1</textVal>
        </hText>
        <hText x="10" y="30">
            <textVal>TEXT 2</textVal>
        </hText>
        <hText x="10" y="40">
            <textVal>TEXT 3</textVal>
        </hText>
    </head>
    <body/>
</report>

And I'm trying to transform it using the following XSLT stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xpath-default-namespace="http://jasperreports.sourceforge.net/jasperreports"
  xmlns:jsp="http://jasperreports.sourceforge.net/jasperreports"
  xmlns="http://jasperreports.sourceforge.net/jasperreports"
  exclude-result-prefixes="xs jsp"
  expand-text="yes"
  version="3.0">


<xsl:param name="doc2"  xmlns="">
    <secondDoc>
    <elementTemps>
        <elemTemp ID="1" name="FirstElementTemp" />
        <elemTemp ID="2" name="SecondTemplate" />
    </elementTemps>
    <elementReps>
        <elemRep tmpID="1" name="FirstElementRep" >
            <value forCDATA="THIS IS THE VALUE FOR CDATA 1">FIRST DATA 1</value>
            <value forCDATA="THIS IS THE VALUE FOR CDATA 1">FIRST DATA 2</value>
            <value forCDATA="THIS IS THE VALUE FOR CDATA 1">FIRST DATA 3</value>
        </elemRep>
        <elemRep tmpID="2" name="SecondTemplate">
            <value forCDATA="THIS IS THE VALUE FOR CDATA 2">SECOND DATA</value>
        </elemRep>
    </elementReps>
    </secondDoc>     
  </xsl:param>

<xsl:output indent="yes" cdata-section-elements="element1"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:key name="key1" match="elemTemp" use="@name" xpath-default-namespace=""/>
  <xsl:key name="key2" match="elemRep" use="@tmpID" xpath-default-namespace=""/>

 <xsl:template match="report/*[1]">
    <xsl:variable name="temp" select="key('key1', ../@repName, $doc2)"/>
    <xsl:variable name="rep" select="key('key2', $temp/@ID, $doc2)"/>
    <valueIs>
        <xsl:value-of select="$rep/value[1]" xpath-default-namespace=""/>
    </valueIs>
    <element1>
        <xsl:value-of select="$rep/value[1]/@forCDATA" xpath-default-namespace=""/>
    </element1>
</xsl:template> 

<xsl:template match="element2">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
            <newChild>THIS IS THE NEW CHILD</newChild>
    </xsl:copy>
</xsl:template>

<xsl:template match="report/body">
       <xsl:variable name="temp2" select="key('key1', ancestor::report/@repName, $doc2)"/>
      <xsl:variable name="rep2" select="key('key2', $temp2/@ID, $doc2)"/>
     <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:for-each select="$rep2/value" xpath-default-namespace="">
        <xsl:variable name="vCount" select="count(preceding-sibling::value)+1"/>
            <bText>
                    <xsl:attribute name="x">
                        <xsl:value-of select="/report/head/hText[$vCount]/@x"/>
                    </xsl:attribute>
                    <xsl:attribute name="y">
                        <xsl:value-of select="/report/head/hText[$vCount]/@y"/>
                    </xsl:attribute>
                    <textVal>
                        <xsl:value-of select="current()"/>
                    </textVal>
            </bText>
        </xsl:for-each>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

As you can see, I'm using a second XML input document (doc2) that I pass to the XSLT as a <xsl:param>. The section of the XSLT stylesheet that isn't working is the last <xsl:tempplate>, <xsl:template match="report/body">

Basically, this is the output I want to get:

<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://jasperreports.sourceforge.net/jasperreports"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd"
        repName="FirstElementTemp"
        date="10-05-2001">
    <valueIs>FIRST DATA 1</valueIs>
   <element1><![CDATA[THIS IS THE VALUE FOR CDATA 1]]></element1>
    <element2 name="secondElement">
      <newChild>THIS IS THE NEW CHILD</newChild>
   </element2>
    <head>
        <hText x="10" y="20">
            <textVal>TEXT 1</textVal>
        </hText>
        <hText x="10" y="30">
            <textVal>TEXT 2</textVal>
        </hText>
        <hText x="10" y="40">
            <textVal>TEXT 3</textVal>
        </hText>
    </head>
    <body>
      <bText x="10" y="20">
         <textVal>FIRST DATA 1</textVal>
      </bText>
      <bText x="10" y="30">
         <textVal>FIRST DATA 2</textVal>
      </bText>
      <bText x="10" y="40">
         <textVal>FIRST DATA 3</textVal>
      </bText>
   </body>
</report>

But this is the output I'm really getting:

<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://jasperreports.sourceforge.net/jasperreports"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd"
        repName="FirstElementTemp"
        date="10-05-2001">
    <valueIs>FIRST DATA 1</valueIs>
   <element1><![CDATA[THIS IS THE VALUE FOR CDATA 1]]></element1>
    <element2 name="secondElement">
      <newChild>THIS IS THE NEW CHILD</newChild>
   </element2>
    <head>
        <hText x="10" y="20">
            <textVal>TEXT 1</textVal>
        </hText>
        <hText x="10" y="30">
            <textVal>TEXT 2</textVal>
        </hText>
        <hText x="10" y="40">
            <textVal>TEXT 3</textVal>
        </hText>
    </head>
    <body>
      <bText x="" y="">
         <textVal>FIRST DATA 1</textVal>
      </bText>
      <bText x="" y="">
         <textVal>FIRST DATA 2</textVal>
      </bText>
      <bText x="" y="">
         <textVal>FIRST DATA 3</textVal>
      </bText>
   </body>
</report>

As you can see I'm not being able to get the value from <xsl:value-of select="/report/head/hText[$vCount]/@x"/> and <xsl:value-of select="/report/head/hText[$vCount]/@y"/>, to put inside the x and y attributes of the <bText> elements, respectively.

I think this is because in the <xsl:for-each> I go inside the second XML input document (doc2), and then in the <xsl:value-of> elements I try to go back to the first XML input document. Also, I'm using the current() function and so I can confirm that I'm in the context of the second input XML document (doc2).

So what I need to do is change the namespace back to "http://jasperreports.sourceforge.net/jasperreports" or change the context to the context of the first input XML document.

How can I do this? I tried doing <xsl:value-of select="/jsp:report/jsp:head/jsp:hText[$vCount]/@x"/> because I defined that namespace in the <xsl:stylesheet> element but it didn't work.

XSLT FIDDLE AT: https://xsltfiddle.liberty-development.net/94hvTzn

Thank you!

Alexandre Jacinto

1

1 Answers

0
votes

Store the main input doc in a variable and make sure you switch the xpath default namespace back where needed:

    <xsl:variable name="main-doc" select="/"/>
    <xsl:for-each select="$rep2/value" xpath-default-namespace="">
        <xsl:variable name="vCount" select="position()"/>
        <bText xsl:xpath-default-namespace="http://jasperreports.sourceforge.net/jasperreports">
                <xsl:attribute name="x">
                    <xsl:value-of select="$main-doc/report/head/hText[$vCount]/@x"/>
                </xsl:attribute>
                <xsl:attribute name="y">
                    <xsl:value-of select="$main-doc/report/head/hText[$vCount]/@y"/>
                </xsl:attribute>
                <textVal>
                    <xsl:value-of select="current()"/>
                </textVal>
        </bText>
    </xsl:for-each>

https://xsltfiddle.liberty-development.net/94hvTzn/1

In the end it might be easier to declare namespace prefix in the stylesheet for your main input elements and use that where needed to select or match them and then use no prefix for the secondary input document.