Проблема проверки XSD с Java5 - PullRequest
2 голосов
/ 23 апреля 2009

Я пытаюсь проверить фид Atom с Java 5 (JRE 1.5.0 обновление 11). У меня есть код работает без проблем в Java 6, но не работает при запуске в Java 5 с

org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'xml:base' to a(n) 'attribute declaration' component.

Кажется, я помню, что читал кое-что о версии Xerces в комплекте с Java 5, которая имела некоторые проблемы с некоторыми схемами, но я не могу найти обходной путь. Это известная проблема? У меня есть ошибка в моем коде?

public static void validate() throws SAXException, IOException {
    List<Source> schemas = new ArrayList<Source>();
    schemas.add(new StreamSource(AtomValidator.class.getResourceAsStream("/atom.xsd")));
    schemas.add(new StreamSource(AtomValidator.class.getResourceAsStream("/dc.xsd")));

    // Lookup a factory for the W3C XML Schema language
    SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");

    // Compile the schemas.
    Schema schema = factory.newSchema(schemas.toArray(new Source[schemas.size()]));
    Validator validator = schema.newValidator();

    // load the file to validate
    Source source = new StreamSource(AtomValidator.class.getResourceAsStream("/sample-feed.xml"));

    // check the document
    validator.validate(source);
}

Обновление: Я попробовал метод ниже, но у меня все еще есть та же проблема, если я использую Xerces 2.9.0. Я также попытался добавить xml.xsd в список схем (так как xml: base определен в xml.xsd), но на этот раз у меня есть

Exception in thread "main" org.xml.sax.SAXParseException: schema_reference.4: Failed to read schema document 'null', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.

Обновление 2: Я попытался настроить прокси с аргументами виртуальной машины -Dhttp.proxyHost=<proxy.host.com> -Dhttp.proxyPort=8080, и теперь это работает. Я постараюсь опубликовать «реальный ответ» из дома.

и извините, я не могу ответить как комментарий: по соображениям безопасности XHR отключен от работы ...

Ответы [ 3 ]

3 голосов
/ 23 апреля 2009

Действительно, люди упоминали о Java 5 Sun, если SchemaFactory доставляет проблемы.

Итак: вы сами включили Xerces в свой проект?

После включения Xerces вы должны убедиться, что он используется. Если вы хотите жестко закодировать его (ну, в качестве минимального требования вы, вероятно, использовали бы некоторый файл свойств приложения, чтобы включить и заполнить следующий код):

String schemaFactoryProperty = 
  "javax.xml.validation.SchemaFactory:" + XMLConstants.W3C_XML_SCHEMA_NS_URI;

System.setProperty(schemaFactoryProperty,
   "org.apache.xerces.jaxp.validation.XMLSchemaFactory");

SchemaFactory factory = 
  SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

Или, если вы не хотите жестко кодировать или когда ваш проблемный код находится в какой-либо сторонней библиотеке, которую вы не можете изменить, установите его в командной строке java или в параметрах среды. Например (на одной строке, конечно):

set JAVA_OPTS = 
  "-Djavax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema
  =org.apache.xerces.jaxp.validation.XMLSchemaFactory"

Кстати: помимо того, что Sun включила реализацию SchemaFactory, создающую проблемы (что-то вроде com.sun.org.apache.xerces.internal.jaxp.validation.xs.schemaFactoryImpl), также кажется, что «обнаружение» не-JDK-реализаций терпит неудачу в этой версии. Если я правильно понимаю, то, как правило, простое включение Xerces фактически заставит SchemaFactory # newInstance найти эту включенную библиотеку и дать ей приоритет над реализацией Sun. Насколько мне известно, это также не работает в Java 5, поэтому требуется указанная выше конфигурация.

1 голос
/ 24 апреля 2009

Я попытался настроить прокси с аргументами виртуальной машины -Dhttp.proxyHost=<proxy.host.com> -Dhttp.proxyPort=8080, и теперь он работает.

Ах, я не осознавал, что xml.xsd на самом деле упоминается как http://www.w3.org/2001/xml.xsd или что-то в этом роде. Это должно научить нас всегда показывать некоторые фрагменты XML и XSD. ; -)

Итак, правильно ли я предположить, что 1.) для решения проблемы Java 5 вам все еще нужно было включить Xerces и установить системное свойство, и что 2.) у вас не было xml.xsd доступного локально?

До того, как вы нашли свое решение, не пытались ли вы использовать getResource вместо getResourceAsStream, чтобы посмотреть, не исключило ли бы это исключение некоторые дополнительные подробности?

Если у вас действительно есть xml.xsd (так: если getResource действительно выдал URL), то мне интересно, что Xerces тогда пытался получить из Интернета. Или, может быть, вы не добавили эту схему в список до добавления собственных схем? Порядок важен: сначала нужно добавить зависимости.

Для того, кто бы ни получил свой вопрос, используя поиск: возможно, используя пользовательский EntityResolver мог бы также указать источник проблемы (если только записать что-то в журнал и просто вернуть null, чтобы сообщить Xerces для использования поведения по умолчанию).

0 голосов
/ 23 апреля 2009

Хммм, просто прочитайте свой «комментарий» - редактирование не предупреждает людей о новых ответах, поэтому самое время спросить своего начальника о каком-либо iPhone или каком-либо другом гаджете, который напрямую подключен к сети;

Ну, я полагаю, вы добавили:

schemas.add(
  new StreamSource(AtomValidator.class.getResourceAsStream("/xml.xsd")));

Если это так, то действительно ли xml.xsd можно найти на пути к классам? Интересно, если бы getResourceAsStream не принесло null в вашем случае, и как бы тогда действовал new StreamSource(null)?

Даже если getResourceAsStream не даст null, полученный StreamSource все равно не будет знать, откуда он был загружен, что может быть проблемой при попытке включить ссылки. Итак, что если вы используете вместо этого конструктор StreamSource (String systemId) :

schemas.add(new StreamSource(AtomValidator.class.getResource("/atom.xsd")));
schemas.add(new StreamSource(AtomValidator.class.getResource("/dc.xsd")));

Вы также можете использовать StreamSource (InputStream inputStream, String systemId) , но я не вижу никаких преимуществ перед двумя вышеупомянутыми строками. Тем не менее, документация объясняет, почему передача systemId в любом из двух конструкторов кажется хорошей:

Этот конструктор позволяет устанавливать systemID в дополнение к входному потоку, что позволяет обрабатывать относительные URI.

Аналогично, setSystemId (String systemId) объясняет немного:

Системный идентификатор является необязательным, если имеется поток байтов или поток символов, но его все равно полезно предоставить, поскольку приложение может использовать его для разрешения относительных URI и может включать его в сообщения об ошибках и предупреждения (анализатор) будет пытаться открыть соединение с URI, только если не указан ни байтовый поток, ни символьный поток).

Если это не сработает, возможно, какой-то пользовательский обработчик ошибок может дать вам более подробную информацию:

ErrorHandlerImpl errorHandler = new ErrorHandlerImpl();
validator.setErrorHandler(errorHandler);
:
:
validator.validate(source);

if(errorHandler.hasErrors()){
    LOG.error(errorHandler.getMessages());
    throw new [..];
}
if(errorHandler.hasWarnings()){
    LOG.warn(errorHandler.getMessages());
}

... используя следующий ErrorHandler для захвата ошибок проверки и продолжения анализа, насколько это возможно:

import org.xml.sax.helpers.DefaultHandler;
private class ErrorHandlerImpl extends DefaultHandler{
    private String messages = "";
    private boolean validationError = false;
    private boolean validationWarning = false;

    public void error(SAXParseException exception) throws SAXException{
        messages += "Error: " + exception.getMessage() + "\n";
        validationError = true;
    }

    public void fatalError(SAXParseException exception) throws SAXException{
        messages += "Fatal: " + exception.getMessage();
        validationError = true;
    }

    public void warning(SAXParseException exception) throws SAXException{
        messages += "Warn: " + exception.getMessage();
        validationWarning = true;
    }

    public boolean hasErrors(){
        return validationError;
    }

    public boolean hasWarnings(){
        return validationWarning;
    }

    public String getMessages(){
        return messages;
    }
}
...