Получить пространство имен xml (без запуска UnknownHostException)

У меня есть некоторый код Java, который определяет пространство имен элемента корневого уровня документа xml с использованием SAX. Если пространство имен «http://sbgn.org/libsbgn/pd/0.1», оно должно вернуть версию 1. Если пространство имен «http://sbgn.org/libsbgn/0.2», версия должна быть 2. Таким образом, весь код читает первый элемент и устанавливает переменную на основе пространства имен. Вот код:

private static class VersionHandler extends DefaultHandler
{
    private int version = -1;

    @Override
    public void startElement (String uri, String localName, String qName, Attributes attributes) throws SAXException
    {
        if ("sbgn".equals (qName))
        {
            System.out.println (uri);
            if ("http://sbgn.org/libsbgn/0.2".equals(uri))
            {
                version = 2;
            } 
            else if ("http://sbgn.org/libsbgn/pd/0.1".equals(uri))
            {
                version = 1;
            } 
            else
            {
                version = -1;
            }
        }
    }

    public int getVersion() { return version; }
};

public static int getVersion(File file) throws SAXException, FileNotFoundException, IOException
{
    XMLReader xr;   
    xr = XMLReaderFactory.createXMLReader();

    VersionHandler versionHandler = new VersionHandler();

    xr.setContentHandler(versionHandler);
    xr.setErrorHandler(versionHandler);
    xr.parse(new InputSource(
        InputStreamToReader.inputStreamToReader(
            new FileInputStream (file))));

    return versionHandler.getVersion();
}   

Это работает, но есть две проблемы:

  1. Это неэффективно, потому что будет проанализирован весь документ, даже если нужен только первый элемент.
  2. Что еще более важно, этот код иногда (очевидно, в зависимости от конфигурации брандмауэра) вызывает UnknownHostException следующим образом:
    java.net.UnknownHostException: www.w3.org 
    at java.net.PlainSocketImpl.connect(Unknown Source)
    at java.net.SocksSocketImpl.connect(Unknown Source)
    at java.net.Socket.connect(Unknown Source)
    at java.net.Socket.connect(Unknown Source)
    at sun.net.NetworkClient.doConnect(Unknown Source)
    at sun.net.www.http.HttpClient.openServer(Unknown Source)
    at sun.net.www.http.HttpClient.openServer(Unknown Source)
    at sun.net.www.http.HttpClient.(Unknown Source)
    at sun.net.www.http.HttpClient.New(Unknown Source)
    at sun.net.www.http.HttpClient.New(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(Unknown
    Source)
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown
    Source)
    at
    com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(Unknown
    Source)
    at
    com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(Unknown
    Source)
    at
    com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startDTDEntity(Unknown
    Source)
    at
    com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.setInputSource(Unknown
    Source)
    at
    com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.dispatch(Unknown
    Source)
    at
    com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.next(Unknown
    Source)
    at
    com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(Unknown
    Source)
    at
    com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown
    Source)
    at
    com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown
    Source)
    at
    com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown
    Source)
    at
    com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown
    Source)
    at
    com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown
    Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown
    Source)
    at
    com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown
    Source)
    at org.sbgn.SbgnVersionFinder.getVersion(SbgnVersionFinder.java:57)

Итак, мои вопросы:

  1. По-видимому, этот фрагмент кода подключается к Интернету. Как я могу этого избежать? Помимо того, что это приводит к проблемам с брандмауэрами, он также излишне медленный.
  2. Почему он подключается к Интернету? Пожалуйста, помогите мне понять логику здесь, в этом не должно быть абсолютно никакой необходимости.
  3. Есть ли более эффективный способ определить пространство имен корневого элемента XML-документа?

Изменить: вот ссылка на образец документа, который я пытаюсь разобрать следующим образом: https://libsbgn.svn.sourceforge.net/svnroot/libsbgn/trunk/test-files/PD/adh.sbgn

Edit2: примечание относительно решения этой ошибки: на самом деле проблема была вызвана тем, что анализировался неправильный документ, вместо предполагаемого документа я анализировал документ XHMTML, который на самом деле ссылается на www.w3.org. Конечно, решение состоит в том, чтобы использовать правильный документ. Тем не менее, я счел полезным добавить эту строку:

 xr.setEntityResolver(null);

Чтобы предотвратить переход xerces через Интернет, когда это действительно совершенно не нужно.


person amarillion    schedule 10.08.2011    source источник


Ответы (2)


Я считаю, что вам нужно установить распознаватель сущностей. См. javadoc. Кроме того, эта статья кажется актуальной.

person Dilum Ranatunga    schedule 10.08.2011
comment
Я просто не понимаю. Я ни в коем случае не ссылаюсь на сайт www.w3.org. Я добавил ссылку на образец документа в конце. - person amarillion; 11.08.2011
comment
Наконец-то я знаю, что вызвало проблему, в данном случае был передан совершенно неверный XML-документ, который на самом деле ссылался на www.w3.org. Это объясняет сообщение об ошибке. Настоящим решением было, конечно, передать правильный XML, но все же я установил xr.setEntityResolver(null); для предотвращения ненужного перехода через Интернет. - person amarillion; 23.08.2011

Вероятно, он подключается к Интернету, потому что ваш документ ссылается на DTD или другой внешний объект на веб-сайте W3C. Ранее в этом году W3C прекратил обслуживание этих документов, потому что они не могли обрабатывать трафик.

Вы можете решить проблему чтения всего документа, сгенерировав SAXException из одного из ваших обратных вызовов, как только вы просмотрите столько документа, сколько вам нужно. Убедитесь, что код, вызывающий метод XMLReader.parse(), отличает это исключение от исключений, выдаваемых самим синтаксическим анализатором (например, вы можете создать подкласс SAXException: хотя не все синтаксические анализаторы выдают ваше исходное исключение без изменений, и вам, возможно, придется поэкспериментировать. )

person Michael Kay    schedule 10.08.2011
comment
W3C перестал обслуживать эти документы, потому что они не могли справиться с трафиком — что ж, я не удивлен, учитывая, что стандартные библиотеки делают эти запросы по умолчанию, даже без ведома программиста! - person amarillion; 11.08.2011
comment
@amarillion, я разделяю ваше возмущение. Я думаю, это нелепо, что стандартные документы не упакованы с парсерами XML. Извлечение ресурсов из пути к классам — элегантное решение для такого статического контента. - person Dilum Ranatunga; 11.08.2011