StAX и пространства имен

Я пытаюсь преобразовать некоторый код с использованием DOM (через jDOM) для использования вместо этого StAX. В то же время я перехожу от проверки на основе DTD к проверке на основе XSD. О, и просто для верности я ввожу в уравнение JAXB :)

В любом случае, в качестве промежуточного шага миграции я хотел бы позволить пользователям по-прежнему предоставлять устаревшие документы (иначе говоря, с использованием DTD и, следовательно, без пространства имен). Я по-прежнему буду проверять документ с помощью XSD, поэтому DTD игнорируется. Это работает, за исключением того, что StAX (или JAXB), похоже, не нравится документ без пространства имен. Я попытался отключить поддержку пространства имен (используя javax.xml.stream.isNamespaceAware), но это не дало никакого эффекта. Явное добавление xmlns в корень документа устранило проблему, поэтому я вполне уверен, что это проблема пространства имен.

Можно ли с помощью StAX XMLEventReader «ввести» пространство имен по умолчанию? Что-то вроде этого подхода(который специфичен для SAX), но для StAX...

Или какие-нибудь другие идеи о том, как этого добиться?

Пример документа выглядит следующим образом:




    ...

Код, который я сейчас использую для чтения этих документов:

public JaxbRoot unmarshal(InputStream stream, Origin origin) {
    try {
        XMLEventReader staxReader = staxFactory().createXMLEventReader( stream );
        try {
            return unmarshal( staxReader, origin );
        }
        finally {
            try {
                staxReader.close();
            }
            catch ( Exception ignore ) {
            }
        }
    }
    catch ( XMLStreamException e ) {
        throw new MappingException( "Unable to create stax reader", e, origin );
    }
}

private XMLInputFactory staxFactory;

private XMLInputFactory staxFactory() {
    if ( staxFactory == null ) {
        staxFactory = buildStaxFactory();
    }
    return staxFactory;
}

@SuppressWarnings( { "UnnecessaryLocalVariable" })
private XMLInputFactory buildStaxFactory() {
    XMLInputFactory staxFactory = XMLInputFactory.newInstance();
    // tried with and without, no effect
    //staxFactory.setProperty( "javax.xml.stream.isNamespaceAware", false );
    return staxFactory;
}

@SuppressWarnings( { "unchecked" })
private JaxbRoot unmarshal(XMLEventReader staxEventReader, final Origin origin) {
    XMLEvent event;
    try {
        event = staxEventReader.peek();
        while ( event != null && !event.isStartElement() ) {
            staxEventReader.nextEvent();
            event = staxEventReader.peek();
        }
    }
    catch ( Exception e ) {
        throw new MappingException( "Error accessing stax stream", e, origin );
    }

    if ( event == null ) {
        throw new MappingException( "Could not locate root element", origin );
    }

    final Schema validationSchema;
    final Class jaxbTarget;

    final String elementName = event.asStartElement().getName().getLocalPart();

    if ( "entity-mappings".equals( elementName ) ) {
        final Attribute attribute = event.asStartElement().getAttributeByName( ORM_VERSION_ATTRIBUTE_QNAME );
        final String explicitVersion = attribute == null ? null : attribute.getValue();
        validationSchema = validateXml ? resolveSupportedOrmXsd( explicitVersion ) : null;
        jaxbTarget = JaxbEntityMappings.class;
    }
    else {
        validationSchema = validateXml ? hbmSchema() : null;
        jaxbTarget = JaxbHibernateMapping.class;
    }

    final Object target;
    final ContextProvidingValidationEventHandler handler = new ContextProvidingValidationEventHandler();
    try {
        JAXBContext jaxbContext = JAXBContext.newInstance( jaxbTarget );
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        unmarshaller.setSchema( validationSchema );
        unmarshaller.setEventHandler( handler );
        target = unmarshaller.unmarshal( staxEventReader );
    }
    catch ( JAXBException e ) {
        throw new MappingException( ... );
    }

    return new JaxbRoot( target, origin );
}

В моем тестировании наличие или отсутствие DTD не имеет значения. И, как я уже говорил ранее, простое изменение


на


устраняет ошибки, которые я вижу, а именно:

[org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'hibernate-mapping'.]
    at ...
Caused by: org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'hibernate-mapping'.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:195)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:131)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:384)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:318)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(XMLSchemaValidator.java:1916)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(XMLSchemaValidator.java:705)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.startElement(ValidatorHandlerImpl.java:550)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.ValidatingUnmarshaller.startElement(ValidatingUnmarshaller.java:78)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:60)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.StAXEventConnector.handleStartElement(StAXEventConnector.java:247)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.StAXEventConnector.bridge(StAXEventConnector.java:116)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:394)
    ... 27 more

5
задан Community 23 May 2017 в 11:46
поделиться