как я могу сказать xalan НЕ проверять XML, полученный с помощью функции «документ»? - PullRequest
6 голосов
/ 30 июня 2011

Вчера Oracle решила временно отключить java.sun.com.Это испортило мне жизнь, потому что xalan пытался проверить некоторый XML, но не смог получить properties.dtd.

Я использую xalan 2.7.1 для запуска некоторых XSL-преобразований, и мне это не нужночтобы подтвердить что-либо.поэтому попытался загрузить XSL следующим образом:

SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
spf.setValidating(false);
XMLReader rdr = spf.newSAXParser().getXMLReader();      
Source xsl = new SAXSource(rdr, new InputSource(xslFilePath));  
Templates cachedXSLT  = factory.newTemplates(xsl);
Transformer transformer = cachedXSLT.newTransformer();         
transformer.transform(xmlSource, result);  

в самом XSL, я делаю что-то вроде этого:

  <xsl:variable name="entry" select="document(concat($prefix, $locale_part, $suffix))/properties/entry[@key=$key]"/>

XML-код, который получает этот код, имеет следующее определение вверху:

<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="...

Несмотря на приведенный выше код java, который инструктирует синтаксический анализатор NOT VALIDATE, он все равно отправляет запрос на java.sun.com.Пока java.sun.com недоступен, это приводит к сбою преобразования с сообщением:

 Can not load requested doc: http://java.sun.com/dtd/properties.dtd

Как заставить xalan прекратить попытки проверить XML, загруженный из функции «document»?

Ответы [ 5 ]

3 голосов
/ 22 февраля 2012

В документации упоминается, что синтаксический анализатор может читать DTD, даже если он не проверяется, поскольку может возникнуть необходимость использовать DTD для разрешения (расширения) сущностей.

Поскольку у меня нет контроля над XMLдокументы, у нет возможности изменить XML , которая была мне недоступна.

Мне удалось остановить попытки извлечения документов DTD путем саботажа решателя следующим образом.

Мой код использует DocumentBuilder для возврата документа (= DOM), но XMLReader согласно примеру OP также имеет метод setEntityResolver, поэтому тот же метод должен работать с этим.

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false); // turns off validation
factory.setSchema(null);      // turns off use of schema
                              // but that's *still* not enough!
builder = factory.newDocumentBuilder();
builder.setEntityResolver(new NullEntityResolver()); // swap in a dummy resolver
return builder().parse(xmlFile); 

Здесь, сейчас, это мой поддельный распознаватель: он возвращает пустой InputStream независимо от того, о чем его просят.

/** my resolver that doesn't */
private static class NullEntityResolver implements EntityResolver {

    public InputSource resolveEntity(String publicId, String systemId) 
    throws SAXException, IOException {
        // Message only for debugging / if you care
        System.out.println("I'm asked to resolve: " + publicId + " / " + systemId);
        return new InputSource(new ByteArrayInputStream(new byte[0]));
    }

}

В качестве альтернативы, ваш поддельный распознаватель может возвращать потоки фактических документов, считанных как локальные ресурсы или как угодно.

3 голосов
/ 30 июня 2011

Имейте в виду, что отключение загрузки DTD приведет к сбою синтаксического анализа, если DTD определяет какие-либо объекты, от которых зависит ваш XML-файл. Тем не менее, чтобы отключить загрузку DTD, попробуйте следующее: предполагается, что вы используете Xerces по умолчанию, который поставляется с Java.

    /*
     * Instantiate the SAXParser and set the features to prevent loading of an external DTD
     */
   SAXParser sp = SAXParserFactory.newInstance().newSAXParser();
   XMLReader xrdr = sp.getXMLReader();
   xrdr.setFeature("http://xml.org/sax/features/validation", false);
   xrdr.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

Если вам действительно нужен DTD, то другой альтернативой является реализация локального каталога XML

    /*
     * Instantiate the SAXParser and add catalog support
     */
   SAXParser sp = SAXParserFactory.newInstance().newSAXParser();
   XMLReader xrdr = sp.getXMLReader();

   CatalogResolver cr = new CatalogResolver();
   xrdr.setEntityResolver(cr);

На что вам нужно будет предоставить соответствующие DTD и определение каталога XML. Эта статья Википедии и эта статья были полезны.

CatalogResolver просматривает системное свойство xml.catalog.files, чтобы определить, какие каталоги загружать.

1 голос
/ 30 июня 2011

Попробуйте использовать setFeature на SAXParserFactory.

Попробуйте это:

SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setValidating(false);
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

Я думаю, этого должно быть достаточно, в противном случае попробуйте установить несколько других функций:

spf.setFeature("http://xml.org/sax/features/validation", false);
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
0 голосов
/ 31 декабря 2015

Извините за некропостинг, но я нашел решение, которое действительно работает, и решил, что должен поделиться им.

1. По какой-то причине setValidating (false) не работает. В некоторых случаях он по-прежнему загружает внешние файлы DTD. Чтобы предотвратить это, вы должны прикрепить пользовательский EntityResolver, как указано здесь :

XMLReader rdr = spf.newSAXParser().getXMLReader();      
rdr.setEntityResolver(new MyCustomEntityResolver());

EntityResolver будет вызываться для каждого запроса внешнего объекта. Возвращение null не будет работать, потому что фреймворк все равно загрузит файл из Интернета после этого. Вместо этого вы можете вернуть пустой поток, который является допустимым DTD, как указано здесь :

private class MyCustomEntityResolver implements EntityResolver {
    public InputSource resolveEntity(String publicId, String systemId) {
        return new InputSource(new StringReader(""));
    }
}

2. Вы говорите setValidating (false) парсеру SAX, который читает ваш XSLT-код. То есть он не будет проверять ваш XSLT. Когда он сталкивается с функцией document (), он загружает связанный XML-файл, используя другой анализатор, который все еще проверяет его, а также загружает внешние объекты. Чтобы справиться с этим, вы должны прикрепить пользовательский URIResolver к преобразователю:

Transformer transformer = cachedXSLT.newTransformer();
transformer.setURIResolver(new MyCustomURIResolver());

Преобразователь вызовет вашу реализацию URIResolver, когда встретит функцию document (). Ваша реализация должна будет вернуть Source для переданного URI. Самое простое - вернуть StreamSource в соответствии с рекомендациями здесь . Но в вашем случае вы должны проанализировать документ самостоятельно, не допуская проверки и внешних запросов, используя уже настроенный SAXParser (или каждый раз создавать новый).

private class MyCustomURIResolver implements URIResolver {
    public Source resolve(String href, String base) {
        return new SAXSource(rdr,new InputSource(href));
    }
}

Так что вам придется реализовать два пользовательских интерфейса в вашем коде.

0 голосов
/ 08 июля 2011

Я только что закончил тем, что удалил объявление doctype из XML, потому что больше ничего не работало. Когда я доберусь до этого, я попробую это: http://www.sagehill.net/docbookxsl/UseCatalog.html#UsingCatsXalan

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