Чрезвычайно медленное XSLT-преобразование в Java - PullRequest
4 голосов
/ 26 января 2011

Я пытаюсь преобразовать XML-документ, используя XSLT.В качестве входных данных у меня есть www.wordpress.org исходный код XHTML, а XSLT - это фиктивный пример получения заголовка сайта (на самом деле он ничего не может сделать - он ничего не меняет).

Каждый используемый мной API или библиотекатрансформация занимает около 2 минут!Если вы посмотрите на источник wordpress.org, вы заметите, что это всего 183 строки кода.Как я гуглил, это, вероятно, связано с построением дерева 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 остановлена ​​...

Есть ли у вас опыт преобразования XML-строк длиннее 50 (это случайное число;)) строк?Поскольку я читаю, XSLT всегда должен строить дерево DOM, чтобы выполнять свою работу.Для меня очень важно быстрое преобразование.

Заранее спасибо, Петр

Ответы [ 4 ]

9 голосов
/ 26 января 2011

Использует ли образец HTML-файла пространства имен?Если это так, ваш анализатор XML может пытаться получить содержимое (возможно, схему) из URI пространства имен.Это вероятно, если каждый запуск занимает ровно две минуты - это, вероятно, один или несколько тайм-аутов TCP.

Вы можете проверить это по времени, сколько потребуется времени для создания экземпляра вашего InputSource объекта (где фактически WordPress XMLразбор), так как это, скорее всего, линия, которая вызывает задержку.После просмотра размещенного вами примера файла в нем есть объявленное пространство имен (xmlns="http://www.w3.org/1999/xhtml").

Чтобы обойти это, вы можете реализовать свой собственный EntityResolver, который по существу отключает URLразрешениеВозможно, вам придется использовать DOM - см. DocumentBuilder setEntityResolver метод.

Вот пример использования 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, вам придется использовать SAXSource с XMLReader, который использует ваш собственный распознаватель.

2 голосов
/ 26 января 2011

Комментаторы, которые опубликовали, что ответ, скорее всего, находится в 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;
    }
    }
});
1 голос
/ 26 января 2011

Скорее всего, проблема не в вызове transfomer.transform. Скорее всего, вы делаете что-то в вашем xslt, что требует вечности. Я бы предложил использовать такой инструмент, как Oxygen или XML Spy, чтобы профилировать ваш XSLT и выяснить, какие шаблоны выполняются дольше всего. Как только вы определились с этим, вы можете начать оптимизировать шаблон.

0 голосов
/ 26 февраля 2013

Если вы отлаживаете код на устройстве Android, обязательно попробуйте его без затмения, прикрепленного к процессу. Когда я отлаживал свое приложение, преобразования xslt занимали 8 секунд, тогда как тот же процесс занимал десятую долю секунды на ios в собственном коде. Как только я запустил код без прикрепленного к нему затмения, процесс занял сопоставимое количество времени с аналогом на основе c.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...