未定义有效布尔值 - XSLT

Posted

技术标签:

【中文标题】未定义有效布尔值 - XSLT【英文标题】:Effective boolean value not defined - XSLT 【发布时间】:2020-08-18 19:30:13 【问题描述】:

我在对 XML 文件应用转换时收到此错误(即未定义有效布尔值)。这里有一个奇怪的问题:

*我的应用程序从一个文件位置读取 500 到 800 个 XML 文件(XML 文件大小范围从几 KB 到 10MB),然后对每个文件进行转换。最初一切都很顺利,但经过一些执行后,它会抛出以下错误:

productsFromLOC_v3.xsl 的第 651 行出错: FORG0006: 有效布尔值未定义 在 xsl:call-template name="AssetStream" (文件:/C:/app/comp/nfs/services/transformer/productsFromLOC_v3.xsl#378) 在 xsl:call-template name="产品" (文件:/C:/app/comp/nfs/services/transformer/productsFromLOC_v3.xsl#53)

第 651 行是:xsl:if test="fn:string-length( fn:copy-of($vStruct)) != 0"

一旦在转换时开始出现此错误,请停止所有转换然后导致相同的错误。

如果我选择那些错误的 XML 文件,然后单独处理,那么根本没有问题。似乎批量 XML 转换只会导致这个问题。

在这种情况下有人可以帮助我吗?

Saxon EE 版本 - 9.8.0.7J 和 XSLT 版本 - 3.0

Java 代码:

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(); 

导致错误的 XSLT 部分:

<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>

【问题讨论】:

如果您详细说明您使用的 Saxon 的版本和版本,以及您运行转换的代码,这总是有帮助的,尤其是在您说“批量 XML 转换”导致问题的情况下。因此,如果单个 XSLT 使用 uri-collectioncollection 一次性处理所有这些文件,那么请准确显示,如果您有 Java 或 C# 管道代码来针对所有文件运行样式表,则显示该代码。 我添加了 XSLT 代码、Java 代码、用于处理的 Saxon 版本。转换的java代码用于其他服务,它从未抱怨过。我尝试通过相同的转换处理 200 个 XML 文件,一切都很顺利。但是我的应用程序可以预期一次有 1500 个 XML 文件进入文件夹进行处理。我们正在运行 mule 3.9.0 EE 版本来从网络文件共享中读取这些文件 问题中的xsl:if test="fn:string-length( fn:copy-of($vStruct)) != 0" 现在是代码sn-p 中的xsl:if test="fn:string-length( fn:copy-of($vStruct)) ne 0" 吗?我无法解释该错误,但在初始参数声明 xsl:param name="vStruct" select="'' " as="xs:string" 中使用 xs:string 而然后传递 map 元素似乎建议您宁愿想要 xsl:param name="vStruct" as="element(fn:map)*" select="()" xmlns:fn="http://www.w3.org/2005/xpath-functions" 然后您想检查 if (not($vStruct)) 或 @ 987654332@. 这种问题最好作为 Saxonica (saxonica.plan.io) 的错误报告来处理。恐怕除非我们能重现问题,否则我们将无能为力。我从您的描述中了解到,构建 repro 并不容易,但这显然是一个复杂的问题,需要进行一些调试。 作为一个实验,尝试每次创建新的 XdmDestination 对象,而不是重复使用它们。我怀疑这是问题所在,但值得消除。 【参考方案1】:

作为实验,请关闭字节码生成。 (FeatureKeys.GENERATE_BYTE_CODE)

当一个构造被执行了一定次数时,字节码生成就会启动,这与您的观察一致,即失败仅在运行一定数量的转换后发生,并且如果您运行这些转换就不会发生一个人。

我认为问题很可能是由错误的字节码生成引起的。如果事实证明是这样,我们显然希望您帮助我们找到实际的错误(而不是仅仅解决它):为此,尝试以较低的字节码生成阈值运行,以便它更快地启动(FeatureKeys.THESHOLD_FOR_HOTSPOT_BYTECODE )。

我还鼓励您在 Saxon 10.0 上试用它。完全有可能是已经修复的bug。

【讨论】:

谢谢你,Michael,我会一一尝试这两个选项,然后回来更新。 我现在已经设法解决了这个问题。问题主要是在 IF 语句开始执行之前未初始化 vStruct - 这导致不存在有效的布尔值。我在 xsl:if 语句调用之前将 vStruct 创建为 xsl:variable。

以上是关于未定义有效布尔值 - XSLT的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS将布尔值传递给指令是未定义的

运营商 !对于参数类型未定义布尔值

使用 jquery 访问设置为 attr 的 Mongoose 模式键(布尔值),但它返回未定义

如何创建布尔值?

关于if判断布尔类型以及a==b的情况

JavaScript中布尔值为false的几种情况