重复使用 xalan 变压器导致其扩展功能中断

发布于 2024-10-12 09:26:04 字数 5813 浏览 2 评论 0原文

我正在使用 xalan 2.7.1 通过 xslt 样式表验证我的 xml 文档。它适用于第一个文档,并通过使用 NodeInfo.lineNumber 和 NodeInfo.columnNumber 扩展在出现错误时返回错误消息以及 xml 源的正确行号和列号。

问题是,当我尝试重用转换器来验证其他 xml 文档时,它成功转换了文档,但对于所有错误始终返回 lineNumber=columnNumber=-1。
有什么想法吗?

编辑:这是我的代码::

package mycompany;

import java.io.File;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.xalan.processor.TransformerFactoryImpl;

public class XsltTransformer {

    public static void main(String[] args) {

        TransformerFactory tFactory = TransformerFactory.newInstance();
        tFactory.setAttribute(TransformerFactoryImpl.FEATURE_SOURCE_LOCATION, Boolean.TRUE);

        StreamSource xsltStreamSource = new StreamSource(new File("E:\\Temp\\Test\\myXslt.xsl"));
        try {
            Transformer transformer = tFactory.newTransformer(xsltStreamSource);

            File srcFolder = new File("E:\\Temp\\Test");
            for (File file : srcFolder.listFiles()) {
                if (file.getName().endsWith("xml")) {

                    Source source = new StreamSource(file);
                    StreamResult result = new StreamResult(System.out);

                    XsltTransformer xsltTransformer = new XsltTransformer();
                    ErrorListenerImpl errorHandler = xsltTransformer.new ErrorListenerImpl();
                    transformer.setErrorListener(errorHandler);

                    transformer.transform(source, result);

                    if (errorHandler.e != null) {
                        System.out.println("Transformation Exception: " + errorHandler.e.getMessage());
                    }

                    transformer.reset();
                }
            }

        } catch (TransformerException e) {
            e.printStackTrace();
        }
    }

    private class ErrorListenerImpl implements ErrorListener {
        public TransformerException e = null;

        public void error(TransformerException exception) {
            this.e = exception;
        }

        public void fatalError(TransformerException exception) {
            this.e = exception;
        }

        public void warning(TransformerException exception) {
            this.e = exception;
        }
    }
}

编辑:这里是 myXslt.xsl 和 XML 源:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<axsl:stylesheet 
    xmlns:axsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:iso="http://purl.oclc.org/dsdl/schematron" 
    xmlns:sch="http://www.ascc.net/xml/schematron"
    version="1.0" 
    xmlns:nodeinfo="xalan://org.apache.xalan.lib.NodeInfo">

  <axsl:output 
      xmlns:svrl="http://purl.oclc.org/dsdl/svrl" 
      xmlns:schold="http://www.ascc.net/xml/schematron" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      indent="yes" 
      standalone="yes" 
      omit-xml-declaration="no" 
      method="xml" />

  <!--SCHEMA METADATA -->
  <axsl:template match="/">
    <svrl:schematron-output xmlns:svrl="http://purl.oclc.org/dsdl/svrl" xmlns:schold="http://www.ascc.net/xml/schematron" 
                            xmlns:xs="http://www.w3.org/2001/XMLSchema" schemaVersion="ISO19757-3" title="Test ISO schematron file. Introduction mode ">
      <svrl:active-pattern>
        <axsl:apply-templates />
      </svrl:active-pattern>
      <axsl:apply-templates mode="M1" select="/" />
    </svrl:schematron-output>
  </axsl:template>

  <!--RULE -->
  <axsl:template mode="M1" priority="1000" match="//*[@remote-property]">
    <svrl:fired-rule xmlns:svrl="http://purl.oclc.org/dsdl/svrl" xmlns:schold="http://www.ascc.net/xml/schematron" 
                     xmlns:xs="http://www.w3.org/2001/XMLSchema" context="//*[@remote-property]" />

    <!--ASSERT -->
    <axsl:choose>
      <axsl:when test="@remote-property = //@id or @remote-property = //@name" />
      <axsl:otherwise>
        <svrl:failed-assert xmlns:svrl="http://purl.oclc.org/dsdl/svrl" xmlns:schold="http://www.ascc.net/xml/schematron" 
                            xmlns:xs="http://www.w3.org/2001/XMLSchema" test="@remote-property = //@id or @remote-property = //@name">
          <axsl:attribute name="lineNumber">
              <axsl:value-of select="nodeinfo:lineNumber()" />
          </axsl:attribute>
          <axsl:attribute name="columnNumber">
              <axsl:value-of select="nodeinfo:columnNumber()" />
          </axsl:attribute>
          <svrl:text>
            Invalid remote-property: remote class element with this id or name does not exists
      </svrl:text>
        </svrl:failed-assert>
      </axsl:otherwise>
    </axsl:choose>
  </axsl:template>
</axsl:stylesheet>

source1.xml:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <remote-service>
        <class name="Table1" table="table1">
            <id name="col1"/>
            <property name="col2"/>
        </class>
    </remote-service>
    <application>
        <text-field name="field1" remote-property="col1X"/>
    </application>
</root> 

和 source2.xml

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <application>
        <text-field name="field1" remote-property="col1Z"/>
    </application>
</root> 

I am using xalan 2.7.1 to validate my xml docs with xslt style sheet. It works fine for the first document and returns error message in case of error along with correct line and column number of xml source by making use of NodeInfo.lineNumber and NodeInfo.columnNumber extensions.

The problem is when I try to reuse transformer to validate other xml docs, it successfully transforms the document but always returns lineNumber=columnNumber=-1 for all errors.
Any idea?

Edit: Here is my code::

package mycompany;

import java.io.File;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.xalan.processor.TransformerFactoryImpl;

public class XsltTransformer {

    public static void main(String[] args) {

        TransformerFactory tFactory = TransformerFactory.newInstance();
        tFactory.setAttribute(TransformerFactoryImpl.FEATURE_SOURCE_LOCATION, Boolean.TRUE);

        StreamSource xsltStreamSource = new StreamSource(new File("E:\\Temp\\Test\\myXslt.xsl"));
        try {
            Transformer transformer = tFactory.newTransformer(xsltStreamSource);

            File srcFolder = new File("E:\\Temp\\Test");
            for (File file : srcFolder.listFiles()) {
                if (file.getName().endsWith("xml")) {

                    Source source = new StreamSource(file);
                    StreamResult result = new StreamResult(System.out);

                    XsltTransformer xsltTransformer = new XsltTransformer();
                    ErrorListenerImpl errorHandler = xsltTransformer.new ErrorListenerImpl();
                    transformer.setErrorListener(errorHandler);

                    transformer.transform(source, result);

                    if (errorHandler.e != null) {
                        System.out.println("Transformation Exception: " + errorHandler.e.getMessage());
                    }

                    transformer.reset();
                }
            }

        } catch (TransformerException e) {
            e.printStackTrace();
        }
    }

    private class ErrorListenerImpl implements ErrorListener {
        public TransformerException e = null;

        public void error(TransformerException exception) {
            this.e = exception;
        }

        public void fatalError(TransformerException exception) {
            this.e = exception;
        }

        public void warning(TransformerException exception) {
            this.e = exception;
        }
    }
}

Edit: Here are myXslt.xsl and XML sources:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<axsl:stylesheet 
    xmlns:axsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:iso="http://purl.oclc.org/dsdl/schematron" 
    xmlns:sch="http://www.ascc.net/xml/schematron"
    version="1.0" 
    xmlns:nodeinfo="xalan://org.apache.xalan.lib.NodeInfo">

  <axsl:output 
      xmlns:svrl="http://purl.oclc.org/dsdl/svrl" 
      xmlns:schold="http://www.ascc.net/xml/schematron" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      indent="yes" 
      standalone="yes" 
      omit-xml-declaration="no" 
      method="xml" />

  <!--SCHEMA METADATA -->
  <axsl:template match="/">
    <svrl:schematron-output xmlns:svrl="http://purl.oclc.org/dsdl/svrl" xmlns:schold="http://www.ascc.net/xml/schematron" 
                            xmlns:xs="http://www.w3.org/2001/XMLSchema" schemaVersion="ISO19757-3" title="Test ISO schematron file. Introduction mode ">
      <svrl:active-pattern>
        <axsl:apply-templates />
      </svrl:active-pattern>
      <axsl:apply-templates mode="M1" select="/" />
    </svrl:schematron-output>
  </axsl:template>

  <!--RULE -->
  <axsl:template mode="M1" priority="1000" match="//*[@remote-property]">
    <svrl:fired-rule xmlns:svrl="http://purl.oclc.org/dsdl/svrl" xmlns:schold="http://www.ascc.net/xml/schematron" 
                     xmlns:xs="http://www.w3.org/2001/XMLSchema" context="//*[@remote-property]" />

    <!--ASSERT -->
    <axsl:choose>
      <axsl:when test="@remote-property = //@id or @remote-property = //@name" />
      <axsl:otherwise>
        <svrl:failed-assert xmlns:svrl="http://purl.oclc.org/dsdl/svrl" xmlns:schold="http://www.ascc.net/xml/schematron" 
                            xmlns:xs="http://www.w3.org/2001/XMLSchema" test="@remote-property = //@id or @remote-property = //@name">
          <axsl:attribute name="lineNumber">
              <axsl:value-of select="nodeinfo:lineNumber()" />
          </axsl:attribute>
          <axsl:attribute name="columnNumber">
              <axsl:value-of select="nodeinfo:columnNumber()" />
          </axsl:attribute>
          <svrl:text>
            Invalid remote-property: remote class element with this id or name does not exists
      </svrl:text>
        </svrl:failed-assert>
      </axsl:otherwise>
    </axsl:choose>
  </axsl:template>
</axsl:stylesheet>

source1.xml:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <remote-service>
        <class name="Table1" table="table1">
            <id name="col1"/>
            <property name="col2"/>
        </class>
    </remote-service>
    <application>
        <text-field name="field1" remote-property="col1X"/>
    </application>
</root> 

and source2.xml

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <application>
        <text-field name="field1" remote-property="col1Z"/>
    </application>
</root> 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

浅忆流年 2024-10-19 09:26:04

javadoc状态:

重置变压器不是
保证有相同的
URIResolver 或 ErrorListener 对象

您可能必须将 ErrorListener 引用重置为重置转换器的新 ErrorListener。

更新

我没有使用 schematron 库的经验,从我看来,这可能是重置变压器使用该库的问题。

如果您无法重置变压器,您可以使用 XSL 模板工具来避免必须解释每个 Transorm 上的 XSL 表:

import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;

TransformerFactory factory = TransformerFactory.newInstance();

Templates xslTemplate = factory.newTemplates(new StreamSource(new StringReader(xsl)));

稍后通过从中获取变压器来重新使用模板:

Transformer transformer = xslTemplate.newTransformer();

The javadoc states:

The reset Transformer is not
guaranteed to have the same
URIResolver or ErrorListener Objects

You might have to reset your ErrorListener reference to the new ErrorListener of the reset transformer.

update

I have no experience with the schematron library, from what I see it is probably an issue of that library being used by a reset transformer.

If you cannot get it to work resetting the transformer you might be able to use the XSL template facility to prevent having to interpret the XSL sheet on every transorm:

import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;

TransformerFactory factory = TransformerFactory.newInstance();

Templates xslTemplate = factory.newTemplates(new StreamSource(new StringReader(xsl)));

Later re-use the template by getting the transformer from it:

Transformer transformer = xslTemplate.newTransformer();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文