0
votes

I am getting this error (i.e. Effective boolean value not defined) while applying transformation on XML files. There is a strange catch here:

*My application reads 500 to 800 XML files (XML file size range from few KB to 10MB) from a file location, and then does transformation on each of them. Initially everything goes smooth, but after some executions it throws below error:

Error on line 651 of productsFromLOC_v3.xsl:
FORG0006: Effective boolean value is not defined
at xsl:call-template name="AssetStream" (file:/C:/app/comp/nfs/services/transformer/productsFromLOC_v3.xsl#378) at xsl:call-template name="Products" (file:/C:/app/comp/nfs/services/transformer/productsFromLOC_v3.xsl#53)

Line no 651 is: xsl:if test="fn:string-length( fn:copy-of($vStruct)) != 0"

Once this error starts appearing while a transformation, rest all transformation then results in same error.

If I pick those error-ed XML files, and process then individually, then there is no issue at all. Seems as if bulk XML transformation causes this problem only.

Can somebody help me in this scenario?

Saxon EE version - 9.8.0.7J, and XSLT version - 3.0

Java code :

private byte[] transformFromSource(String urlParams, String xslFullPath, final String uriXSLT,
    final String outputXSLTFilePath, String transformParams, final Object xmlSource,
    final String outputEncoding)
    throws SaxonApiException, MalformedURLException, SystemException, UnsupportedEncodingException {

final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
List<XsltExecutable> xsltExecutables = xsltTemplateManager.getTemplates(windowsOS ? xslFullPath.split("\\\\")[xslFullPath.split("\\\\").length - 1].trim() : xslFullPath.trim());
Processor processor = null;
XdmNode xdmNode = null;
XdmDestination xdmDestination1 = new XdmDestination();
XdmDestination xdmDestination2 = new XdmDestination();
for (XsltExecutable xsltExecutable : xsltExecutables) {
    int i = 0;
    final Xslt30Transformer transformer = xsltExecutable.load30();
    final Map<QName, XdmValue> params = new HashMap<QName, XdmValue>();
    if (StringUtils.isNotBlank(uriXSLT)) {
        params.put(new QName("xslt.location.uriXSLTPath"), new XdmAtomicValue(uriXSLT));
    }
    if (StringUtils.isNotBlank(outputXSLTFilePath)) {
        params.put(new QName("xslt.location.outputXSLTPath"), new XdmAtomicValue(outputXSLTFilePath));
    }
    if (StringUtils.isNotBlank(transformParams)) {
        params.put(new QName("xslt.transform.params"), new XdmAtomicValue(transformParams));
    }
    if (StringUtils.isNotBlank(urlParams)) {
        params.put(new QName("http.query.params"), new XdmAtomicValue(urlParams));
    }
    transformer.setStylesheetParameters(params);
    if (xsltExecutables.size() == 1) {
        processor = xsltExecutable.getProcessor();
        if (xmlSource instanceof File) {
            if (((File) xmlSource).isFile()) {
                String inFile = "<file>" + ((File) xmlSource).getAbsolutePath() + "</file>";
                xdmNode = processor.newDocumentBuilder().build(new StreamSource(new ByteArrayInputStream(inFile.getBytes(outputEncoding))));
            }
        } else {
            xdmNode = processor.newDocumentBuilder().build((StreamSource) xmlSource);
        }
        final Serializer serializer = processor.newSerializer(outputStream);
        /* serializer.setOutputProperty(Serializer.Property.METHOD, "xml"); */
        serializer.setOutputProperty(Serializer.Property.INDENT, "yes");
        serializer.setOutputProperty(Serializer.Property.ENCODING, outputEncoding);
        transformer.applyTemplates(xdmNode, serializer);
    } else if (xsltExecutables.size() > 1 && i == 0) {
        processor = xsltExecutable.getProcessor();
        if (xmlSource instanceof File) {
            xdmNode = processor.newDocumentBuilder().build((File) xmlSource);
        } else {
            xdmNode = processor.newDocumentBuilder().build((StreamSource) xmlSource);
        }
        transformer.applyTemplates(xdmNode, xdmDestination1);
    } else if (xsltExecutables.size() > 1 && i == xsltExecutables.size()) {
        final Serializer serializer = processor.newSerializer(outputStream);
        serializer.setOutputProperty(Serializer.Property.INDENT, "yes");
        serializer.setOutputProperty(Serializer.Property.ENCODING, outputEncoding);
        transformer.applyTemplates(xdmNode, serializer);
        transformer.applyTemplates(xdmDestination2.getXdmNode(), serializer);
    } else if (xsltExecutables.size() > 1 && i > 0) {
        transformer.applyTemplates(xdmDestination1.getXdmNode(), xdmDestination2);
        xdmDestination1 = xdmDestination2;
    }
}
processor = null;
xdmNode = null;
xsltExecutables = null;
return outputStream.toByteArray(); }

Section of XSLT which results in error:

<xsl:iterate select="$STEP/STEP-ProductInformation/Assets/Asset[@UserTypeID='PDF' or @UserTypeID='PNG']">
<xsl:param name="vCount" select="1" as="xs:integer"/>
<xsl:param name="vFileCount" select="1" as="xs:integer"/>
<xsl:param name="vStruct" select="'' " as="xs:string"/>
<xsl:on-completion>
    <xsl:variable name="vFileName" select="concat($outputXSLTFilePath,'/Asset-',$vTimestamp,'-',$vFileCount,$vJMSID,'.xml')"/>
    <xsl:variable name="vResult">
        <map xmlns="http://www.w3.org/2005/xpath-functions">
            <array key="assets">
                <xsl:copy-of select="$vStruct"/>
            </array>
            <string key="locale">
                <xsl:value-of select="$vContextID"/>
            </string>
            <string key="exportTime">
                <xsl:value-of select="$vExportTime"/>
            </string>
        </map>
    </xsl:variable>
    <xsl:if test="fn:string-length( fn:copy-of($vStruct)) ne 0">
        <Payload>
            <ControlData>
                <FeedType>Assets</FeedType>
                <FullImport>
                    <xsl:value-of select="$fullUpload"/>
                </FullImport>
                <Resequencing>true</Resequencing>
                <JMSXGroupID>
                    <xsl:value-of select="$vJMSID"/>
                </JMSXGroupID>
                <JMSXGroupSeq>
                    <xsl:value-of select="$vFileCount"/>
                </JMSXGroupSeq>
                <GroupSize>
                    <xsl:value-of select="$vTotalMessages"/>
                </GroupSize>
                <OutboundQueueName>feeds/out/1.0/products</OutboundQueueName>
            </ControlData>
            <Message id="{$vFileCount}">
                <xsl:value-of select="odfn:JsonBS(xml-to-json($vResult,map{ 'indent':true() }))"/>
            </Message>
        </Payload>
    </xsl:if>
</xsl:on-completion>
<xsl:variable name="vX">
    <map xmlns="http://www.w3.org/2005/xpath-functions">
        <string key="id">
            <xsl:value-of select="@ID"/>
        </string>
        <string key="typeId">
            <xsl:value-of select="@UserTypeID"/>
        </string>
        <string key="filename">
            <xsl:value-of select="./Values/Value[@AttributeID='asset.filename']"/>
        </string>
    </map>
</xsl:variable>
<xsl:variable name="vXS">
    <xsl:copy-of select="$vStruct"/>
    <xsl:copy-of select="$vX"/>
</xsl:variable>
<xsl:choose>
    <xsl:when test="$vCount &lt; 50">
        <xsl:next-iteration>
            <xsl:with-param name="vCount" select="$vCount+1"/>
            <xsl:with-param name="vFileCount" select="$vFileCount"/>
            <xsl:with-param name="vStruct">
                <xsl:copy-of select="$vXS"/>
            </xsl:with-param>
        </xsl:next-iteration>
    </xsl:when>
    <xsl:otherwise>
        <xsl:variable name="vFileName" select="concat($outputXSLTFilePath,'/Asset-',$vTimestamp,'-',$vFileCount,$vJMSID,'.xml')"/>
        <xsl:variable name="vResult">
            <map xmlns="http://www.w3.org/2005/xpath-functions">
                <array key="assets">
                    <xsl:copy-of select="$vXS"/>
                </array>
                <string key="locale">
                    <xsl:value-of select="$vContextID"/>
                </string>
                <string key="exportTime">
                    <xsl:value-of select="$vExportTime"/>
                </string>
            </map>
        </xsl:variable>
        <Payload>
            <ControlData>
                <FeedType>Assets</FeedType>
                <FullImport>
                    <xsl:value-of select="$fullUpload"/>
                </FullImport>
                <Resequencing>true</Resequencing>
                <JMSXGroupID>
                    <xsl:value-of select="$vJMSID"/>
                </JMSXGroupID>
                <JMSXGroupSeq>
                    <xsl:value-of select="$vFileCount"/>
                </JMSXGroupSeq>
                <GroupSize>
                    <xsl:value-of select="$vTotalMessages"/>
                </GroupSize>
                <OutboundQueueName>feeds/out/1.0/products</OutboundQueueName>
            </ControlData>
            <Message id="{$vFileCount}">
                <xsl:value-of select="odfn:JsonBS(xml-to-json($vResult,map{ 'indent':true() }))"/>
            </Message>
        </Payload>
        <xsl:next-iteration>
            <xsl:with-param name="vCount" select="1"/>
            <xsl:with-param name="vFileCount" select="$vFileCount+1"/>
            <xsl:with-param name="vStruct" select="''"/>
            <!-- blank -->
        </xsl:next-iteration>
    </xsl:otherwise>
</xsl:choose>

1
It always helps if you detail the version and edition of Saxon you use, as well as the code you run the transformations, especially in this case where you say that "bulk XML transformation" causes the problem. So, if the single XSLT processes all those files in one go with uri-collection or collection, then show that exactly, if you have Java or C# plumbing code to run the stylesheet against all the files, then show that code.Martin Honnen
I have added XSLT code, Java code, version of Saxon used for processing. The java code for transformation is used for other services, and it never complained. I tried processing 200 XML files over same transformation, and everything went GOOD. But my application can expect 1500 XML files coming to folder at a time for processing. We are running mule 3.9.0 EE version to read these files from network file shareSambit Swain
Is xsl:if test="fn:string-length( fn:copy-of($vStruct)) != 0" from the question now xsl:if test="fn:string-length( fn:copy-of($vStruct)) ne 0" in the code snippet? I can't explain the error but the use of xs:string in the initial param declaration xsl:param name="vStruct" select="'' " as="xs:string" while then passing on map elements seems to suggest you rather want xsl:param name="vStruct" as="element(fn:map)*" select="()" xmlns:fn="http://www.w3.org/2005/xpath-functions" and then you want to check if (not($vStruct)) or if (exists($vStruct)).Martin Honnen
This kind of problem is probably best handled as a bug report with Saxonica (saxonica.plan.io). I'm afraid we won't be able to do anything with it unless we can reproduce the problem. I appreciate from your description that constructing a repro isn't going to be easy, but this is clearly a complex problem that is going to take some debugging.Michael Kay
Just as an experiment, try to create new XdmDestination objects each time rather than reusing them. I doubt that's the problem, but it's worth eliminating.Michael Kay

1 Answers

0
votes

As an experiment, please switch off bytecode generation. (FeatureKeys.GENERATE_BYTE_CODE)

Bytecode generation kicks in when a construct has been executed a certain number of times, which is consistent with your observation that the failure only occurs after running a certain number of transformations, and that it doesn't occur if you run those transformations singly.

I think there's a very good chance the problem is caused by incorrect bytecode generation. If that proves to be the case, we would obviously like you to help us find the actual bug (rather than just working around it): for that, try running with a lower threshold for bytecode generation so it kicks in sooner (FeatureKeys.THESHOLD_FOR_HOTSPOT_BYTECODE).

I would also encourage you to try it on Saxon 10.0. It's entirely possible that it's a bug that has been fixed.