Java中的XSLT转换极其缓慢

时间:2011-01-25 21:37:05

标签: java xml xslt

我尝试使用XSLT转换XML文档。作为输入,我有www.wordpress.org XHTML源代码,XSLT是虚拟示例检索站点的标题(实际上它什么都不做 - 它不会改变任何东西)。

我使用的每个API或库,转换大约需要2分钟!如果你看看wordpress.org源代码,你会发现它只有183行代码。正如我用Google搜索,这可能是由于DOM树的构建。无论XSLT多么简单,它总是2分钟 - 所以它确认它与DOM构建有关,但无论如何我不应该花2分钟。

这是一个示例代码(没什么特别的):

  TransformerFactory tFactory = TransformerFactory.newInstance();
   Transformer transformer = null;

   try {
       transformer = tFactory.newTransformer(
           new StreamSource("/home/pd/XSLT/transf.xslt"));

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

   ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

   System.out.println("START");
   try {
       transformer.transform(new SAXSource(new InputSource(
           new FileInputStream("/home/pd/XSLT/wordpress.xml"))),
           new StreamResult(outputStream));
   } catch (TransformerException e) {       
       e.printStackTrace();
   } catch (IOException e) {
       e.printStackTrace();
   }
   System.out.println("STOP");

   System.out.println(new String(outputStream.toByteArray()));

在START和STOP之间,java“暂停”2分钟。如果我查看处理器或内存使用情况,则不会增加任何内容。看起来JVM真的停了......

您是否有过转换长度超过50的XML(这是随机数;))的经验?当我读到XSLT时,总是需要构建DOM树才能完成它的工作。快速转型对我来说至关重要。

提前致谢, 彼得

4 个答案:

答案 0 :(得分:9)

示例HTML文件是否使用命名空间?如果是这样,您的XML解析器可能正在尝试从命名空间URI中检索内容(可能是模式)。如果每次运行只需要两分钟 - 这可能是一次或多次TCP超时。

您可以通过计算实例化InputSource对象(实际解析WordPress XML)所需的时间来验证这一点,因为这可能是导致延迟的行。在查看您发布的示例文件后,它确实包含一个声明的命名空间(xmlns="http://www.w3.org/1999/xhtml")。

要解决此问题,您可以实现自己的EntityResolver,这实际上会禁用基于URL的解决方案。您可能需要使用DOM - 请参阅DocumentBuilder的{​​{3}}方法。

以下是使用DOM并禁用解析的示例(注意 - 这是未经测试的):

try {
    DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbFactory.newDocumentBuilder();
    db.setEntityResolver(new EntityResolver() {

        @Override
        public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
            return null; // Never resolve any IDs
        }
    });

    System.out.println("BUILDING DOM");

    Document doc = db.parse(new FileInputStream("/home/pd/XSLT/wordpress.xml"));

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    TransformerFactory tFactory = TransformerFactory.newInstance();
    Transformer transformer = tFactory.newTransformer(
        new StreamSource("/home/pd/XSLT/transf.xslt"));

    System.out.println("RUNNING TRANSFORM");

    transformer.transform(
            new DOMSource(doc.getDocumentElement()),
            new StreamResult(outputStream));

    System.out.println("TRANSFORMED CONTENTS BELOW");
    System.out.println(outputStream.toString());
} catch (Exception e) {
    e.printStackTrace();
}

如果您想使用SAX,则必须使用setEntityResolver SAXSource使用自定义解析器。

答案 1 :(得分:2)

发布可能存在于EntityResolver中的答案的评论者可能是正确的。但是,解决方案可能不是简单地不加载模式,而是从本地文件系统加载它们。

所以你可以做这样的事情

  db.setEntityResolver(new EntityResolver() {

    @Override
    public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
        try {
        FileInputStream fis = new FileInputStream(new File("classpath:xsd/" + systemId));
        InputSource is  = new InputSource(fis);
        return is
    } catch (FileNotFoundException ex) {
        logger.error("File Not found", ex);
        return null;
    }
    }
});

答案 2 :(得分:1)

问题不在于调用transfomer.transform。你更有可能在你的xslt中做一些永远需要的东西。我的建议是使用像Oxygen或XML Spy这样的工具来分析你的XSLT并找出执行时间最长的模板。一旦确定了这一点,就可以开始优化模板了。

答案 3 :(得分:0)

如果您正在Android设备上调试代码,请确保在没有附加到该进程的eclipse的情况下进行尝试。当我调试我的应用程序xslt转换需要8秒,其中相同的过程在本机代码中的ios上花了十分之一秒。一旦我运行没有附加eclipse的代码,该过程花费了相当多的时间给基于c的对手。