Java использует StAX, чтобы получить дочерние элементы в общем виде - PullRequest
4 голосов
/ 24 ноября 2010

Я пытаюсь использовать StAX (мне это уже не нравится ....)
Кажется, что единственный способ использовать его - это непрерывные условия if-else.
Но самое важное, кажется, что нетспособ связать элемент с его дочерними элементами, если не известно заранее структуру разбираемого документа xml. Это правильно?
Я пробовал следующее: у меня есть этот xml в строке

<ns1:Root xmlns:ns1=\"http://rootNameSpace.com/\">
<ns1:A/>
<ns1:B>
        <Book xmlns=\"http://www.myNameSpace.com\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">
            <Data>
                <Author>John</Author>
                <Edition>1</Edition>
                <PubHouse>Small Publishing House</PubHouse>
                <Price>37.8</Price>
            </Data>
        </Book>
</ns1:B>
</ns1:Root>

Я хотел бы использовать StAX для получения элемента Book, но, похоже, я могу писать только код, который жестко закодировал всю структуру.
Т.е. используйте XMLEventReader и, как только вы получите Book, начните цикл для Data, Author и т. Д.Есть ли общее решение для этого?
Я попробовал следующее, чтобы обойти это: я попытался перейти от String к XMLEventReader и обратно к String, но я не могу получить точное представление String, которое я первоначально использовал (пространства имен находятся вскобки, дополнительные двоеточия и т. д.).

StringBuilder xml = new StringBuilder();
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
String msg = "<ns1:Root xmlns:ns1=\"http://rootNameSpace.com/\"><ns1:A/><ns1:B><Book xmlns=\"http://www.myNameSpace.com\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><Data><Author>John</Author><Edition>1</Edition><PubHouse>Small Publishing House</PubHouse><Price>37.8</Price></Data></Book></ns1:B></ns1:Root>";
InputStream input = new ByteArrayInputStream(msg.getBytes("UTF-8"));
XMLEventReader xmlEventReader = inputFactory.createXMLEventReader(input);
while (xmlEventReader.hasNext())
{

    XMLEvent event = xmlEventReader.nextEvent();
    StringWriter sw = new StringWriter();
    event.writeAsEncodedUnicode(sw);
   xml.append(sw);

}
System.out.println(xml);

Я получаю следующее:

<?xml version="1.0" encoding='UTF-8' standalone='no'?><['http://rootNameSpace.com/']:ns1:Root xmlns:ns1='http://rootNameSpace.com/'><['http://rootNameSpace.com/']:ns1:A></ns1:A><['http://rootNameSpace.com/']:ns1:B><['http://www.myNameSpace.com']::Book xmlns:='http://www.myNameSpace.com' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'><['http://www.myNameSpace.com']::Data><['http://www.myNameSpace.com']::Author>John</Author><['http://www.myNameSpace.com']::Edition>1</Edition><['http://www.myNameSpace.com']::PubHouse>Small Publishing House</PubHouse><['http://www.myNameSpace.com']::Price>37.8</Price></Data></Book></ns1:B></ns1:Root>

Может ли этот случай быть рассмотрен через StAX или DOM - единственное решение?

Ответы [ 2 ]

5 голосов
/ 24 ноября 2010

Я не совсем понимаю, что вы пытаетесь сделать, но если вы хотите, чтобы локальное имя тега вызывало событие START_ELEMENT, вы можете сделать это так:

if (event.getEventType() == START_ELEMENT) {
    QName qname = event.asStartElement().getName()
    System.out.println("Start of element " + qname.getLocalPart());
}

Аналогично, asEndElement, asCharacters и т. Д. Обеспечивают доступ к другим типам узлов.

Лично я обычно нахожу, что XMLStreamReader удобнее для меня в большинстве ситуаций, но я полагаю, что это зависит от варианта использования, а также от ваших личных предпочтений.Совет состоит в том, что чем строже схема, тем проще анализировать данные с помощью StAX.

Возможно, вы также захотите посмотреть JAX-B для автоматической привязки данных XML.*

Редактировать: Вот наивный анализатор StAX с рекурсивным спуском для XML в OP:

@Test
public void recursiveDescentStaxParser( ) throws XMLStreamException,
        FactoryConfigurationError
{
    String msg = "<ns1:Root xmlns:ns1=\"http://rootNameSpace.com/\"><ns1:A/><ns1:B><Book xmlns=\"http://www.myNameSpace.com\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><Data><Author>John</Author><Edition>1</Edition><PubHouse>Small Publishing House</PubHouse><Price>37.8</Price></Data></Book></ns1:B></ns1:Root>";
    XMLStreamReader reader = XMLInputFactory.newFactory( )
            .createXMLStreamReader( new StringReader( msg ) );

    reader.nextTag( );
    readRoot( reader );

}

private void readRoot( XMLStreamReader reader ) throws XMLStreamException
{
    while ( reader.nextTag( ) == XMLEvent.START_ELEMENT )
    {
        QName name = reader.getName( );
        if ( "B".equals( name.getLocalPart( ) ) )
            readBooks( reader );
        else
            reader.nextTag( ); // Empty <A>

    }
}

private void readBooks( XMLStreamReader reader ) throws XMLStreamException
{
    while ( reader.nextTag( ) == XMLEvent.START_ELEMENT )
    {
        QName name = reader.getName( );
        if ( !"Book".equals( name.getLocalPart( ) ) )
            throw new XMLStreamException( name.toString( ) );
        reader.nextTag( ); // Jump to <Data>
        readBook( reader );
        reader.nextTag( ); // Jump to </B>
    }
}

private void readBook( XMLStreamReader reader ) throws XMLStreamException
{
    reader.nextTag( ); // Skip to <Author>
    System.out.println( "Author: " + reader.getElementText( ) );
    reader.nextTag( ); // Skip to <Edition>
    System.out.println( "Edition: " + reader.getElementText( ) );
    reader.nextTag( ); // Skip to <PubHouse>
    System.out.println( "Publisher: " + reader.getElementText( ) );
    reader.nextTag( ); // Skip to <Price>
    System.out.println( "Price: " + reader.getElementText( ) );
    reader.nextTag( ); // Skip to </Book>

}

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

1 голос
/ 20 декабря 2010

Похоже, вы выбрали не тот инструмент: Stax - отличный API для эффективной обработки большого контента.Но если удобство важнее, чем эффективность, да, вам, вероятно, следует рассмотреть модель дерева (не обязательно DOM, лучше, например, XOM) или привязку данных (JAXB или XStream).В частности, Stax, как SAX, основаны на потоке, поэтому вы видите только то, что является текущим событием или токеном.Нет доступа для детей или родителей, потому что нет гарантированного способа получить к ним доступ, поскольку это не всегда возможно, учитывая текущее положение потока.

Но если производительность или использование памяти являются проблемой, вы все равно можете либорассмотрим JAXB (который обычно более эффективен, чем модели деревьев, такие как DOM), или StaxMate .StaxMate - это высокопроизводительное расширение с низким потреблением памяти по сравнению со Stax, и его немного удобнее использовать.В то время как вам все еще нужно перебирать элементы в порядке документа, его подход курсора отображается более естественно с поисками parent-then-children.Так что это может работать для вашего случая.

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