0
votes

I have a xslt file to transform xml file to pdf using apache-fop. But I don't have all information about namespaces in my xslt. It depends on xml. I can analyze xml document in java and get all namespaces from xml. But I don't know how I can pass this namespaces from java to my xslt file and how next declare it in <xsl:stylesheet> tag. Is it possible?

I can't paste my original xslt and xml because it has sensitive data, but I prepared sample files to show my problem:

    <?xml version="1.0" encoding="UTF-8"?>
<ns0:OtherCompany xmlns:ns8="http://www.company.com/schema/SF/definition/type/test"  xmlns:ns0="http://www.company.com/schema/SF/definition/type/a" xmlns:ns7="http://www.company.com/schema/SF/definition/type/b" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <ns0:Header>
      <ns8:From>2018-01-01</ns8:From>
      <ns8:To>2018-12-31</ns8:To>
      <ns8:CheckDate>2019-03-28</ns8:CheckDate>
      <ns7:Code sysCode="1">Report</ns7:Code>
      <ns7:Type>1</ns7:Type>
   </ns0:Header>
   <ns0:Changes>
      <ns7:I>
         <ns8:AmountA>1499142.61</ns8:AmountA>
         <ns8:AmountB>54979.16</ns8:AmountB>
      </ns7:I>
      <ns7:II>
         <ns8:AmountA>3398983.19</ns8:AmountA>
         <ns8:AmountB>1499142.61</ns8:AmountB>
      </ns7:II>
      <ns7:III>
         <ns8:AmountA>3398983.19</ns8:AmountA>
         <ns8:AmountB>1499142.61</ns8:AmountB>
      </ns7:III>
   </ns0:Changes>
</ns0:OtherCompany>

and xslt:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" 
        xmlns:fo="http://www.w3.org/1999/XSL/Format" exclude-result-prefixes="fo" xmlns:ns0="http://www.company.com/schema/SF/definition/type/a" xmlns:ns7="http://www.company.com/schema/SF/definition/type/b">

    <xsl:param name="xmlPathPrefix"/>

    <xsl:template match="/">
        <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
          <fo:layout-master-set>
            <fo:simple-page-master master-name="simpleA4" page-height="30cm" page-width="26cm" margin-top="2cm" margin-bottom="2cm" margin-left="1cm" margin-right="1cm">
              <fo:region-body region-name="xsl-region-body" margin-top=".80in" margin-bottom=".50in"/>
            </fo:simple-page-master>
          </fo:layout-master-set>
          <fo:page-sequence master-reference="simpleA4">
            <fo:flow flow-name="xsl-region-body">
                <fo:block font-size="10pt" font-family="Arial">
                  <fo:table table-layout="fixed" width="100%">                    
                    <fo:table-column column-width="12cm" xsl:use-attribute-sets="columnStyle"/>
                    <fo:table-column column-width="12cm" xsl:use-attribute-sets="columnStyle"/>
                    <fo:table-header>
                        <fo:table-row xsl:use-attribute-sets="columnStyle">
                            <fo:table-cell xsl:use-attribute-sets="centerCellStyle">
                                 <fo:block font-weight="bold">Name</fo:block>
                            </fo:table-cell>
                            <fo:table-cell xsl:use-attribute-sets="centerCellStyle">
                                 <fo:block font-weight="bold">Value</fo:block>
                            </fo:table-cell>
                        </fo:table-row>
                    </fo:table-header>
                    <fo:table-body>
                        <xsl:apply-templates select="$xmlPathPrefix//*[not(contains(name(), 'Content'))]"/>
                    </fo:table-body>
                  </fo:table>
                </fo:block>
            </fo:flow>
          </fo:page-sequence>
         </fo:root>
    </xsl:template>

    <xsl:template match="$xmlPathPrefix//*[not(contains(name(), 'Content'))]">  
        <fo:table-row xsl:use-attribute-sets="columnStyle">    
            <fo:table-cell>
                <fo:block>
                    <xsl:value-of select="sf:addSpaces(local-name(), sf:depth-of-node(.))"/>    
                </fo:block>
            </fo:table-cell> 
            <fo:table-cell xsl:use-attribute-sets="marginColumnStyle">
                <fo:block>
                    <xsl:choose>
                        <xsl:when test="*">
                            <xsl:value-of select="''"/>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:value-of select="current()"/>
                        </xsl:otherwise>
                    </xsl:choose>
                </fo:block>
            </fo:table-cell>                                    
        </fo:table-row>
    </xsl:template>

</xsl:stylesheet>

I want to pass from java param xmlPathPrefix and use it in xslt file in <xsl:template> match attribute

<xsl:template match="/$xmlPathPrefix/values">

or in xsl:apply-templates select attribute

<fo:table-body>
    <xsl:apply-templates select="$xmlPathPrefix//*[not(contains(name(), 'Content'))]"/>
</fo:table-body>

But I get following error:

Type error evaluating ($xmlPathPrefix) in xsl:apply-templates/@select on line 38 column 75 of test.xsl: XPTY0019: The required item type of the first operand of '/' is node(); the supplied value u"ns0:OtherCompany/ns0:Changes..." is an atomic value

How I can pass xmlPathPrefix from java and use it in my xslt? I want pass example string as xmlPathPrefix

"ns0:OtherCompany/ns0:Changes"

The second problem is my namespace, the pathPrefix can be different, but local-name always the same, Example it can be:

"ns0:OtherCompany/ns0:Changes"
"ns10:OtherCompany/ns15:Changes"
"companyType:OtherCompany/companyChanges:Changes"

or more other options. When I have xslt i must declare tag in <xsl:stylesheet> example ns0, ns10, companyType etc. If I not declare it I get error. But I don't know what namespaces is declared in my xml. How I can pass it to xslt?

Example i pass

xmlPathPrefix: "ns10:OtherCompany/ns15:Changes"

and namespaces for this: ns10 and ns15

But I don't know how reach it.

1
Show a minimal but complete sample of the XML together with the corresponding XSLT and wanted FO output and I am sure we can help. XSLT/XPath for sure can read/analyze the namespaces in an XML document without knowing them or create or copy elements in a certain namespace.Martin Honnen
@MartinHonnen I completed my post with sample data. Maybe you can help me now?The Nightmare

1 Answers

1
votes

Do you use an XSLT 2 processor like Saxon 9? Your XSLT code says version="2.0". If you are dealing with various namespaces then one way in XSLT/XPath 2 and later is to use a wildcard * for the namespace prefix e.g. *:OtherCompany/*:Changes will select those elements in any namespace.

To parametrize select expressions you would need to use an XSLT 3 processor like Saxon 9.8 or 9.9 and so called shadow attributes like _select and static parameters:

<?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"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:param name="prefix" as="xs:string" static="yes" select="'/*:root/*:foo'"/>

  <xsl:output indent="yes"/>

  <xsl:template match="/">
      <xsl:apply-templates _select="{$prefix}/*:bar"/>
  </xsl:template>

  <xsl:template match="*:bar">
      <xsl:copy-of select="."/>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/ej9EGco

You would need to use Saxon's s9api programming interface to set static parameters I think.