Как сделать демонтаж различных объектов в зависимости от полученного XML?

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

Итак, я получаю такие XML-файлы:

<root>
    <user>
        <id>1234</id>
    </user>
    <XMLelements>
        ...
    </XMLelements>
</root>

Заметить, что XMLelements является примером имени тега, каждый файл XML может иметь разные имена.

Так что, я думаю, мой рабочий процесс веб-службы должен выглядеть примерно так:

  1. Он получает файл XML.
  2. Проверяет идентификатор пользователя.
    • Если идентификатор пользователя == 1234
      • UserA userA = unmarshalling (XMLFile)
    • Иначе, если идентификатор пользователя == 5678
      • UserB userB = unmarshalling (XMLFile)
    • еще
      • UserC userC = unmarshalling(XMLFile)

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

Как я могу выполнить этот подход? Я использую Spring для сортировки (Metro).

Изменить: Этот вопрос не получил никакого ответа, может быть, я не ясно. Я постараюсь объяснить это лучше:

У меня есть веб-сервис, который прослушивает URL-адрес, где получает файлы XML. Фактически, по одному и тому же пути URL мой веб-сервис получает две разные XML-схемы. Как я могу узнать, как правильно выполнять демаршаллинг? Я имею в виду, unmarshalling должен возвращать правильный объект, когда передаются разные XML-схемы.

1 ответ

Решение

Есть несколько разных способов поддержки этого варианта использования.


ВАРИАНТ № 1 - DOM-подход

Вы всегда можете использовать DOM-парсер для преобразования XML в Document выполнить XPath против него, чтобы получить значение id элемент, а затем распаковать документ на основе результата


ВАРИАНТ № 2 - САКС Подход

LookAheadUnmarshallerHandler

Вы могли бы использовать парсер SAX и JAXB UnmarshallerHandler механизм и сделать следующее:

  • Создать ContentHandler это ставит в очередь события SAX, пока не будет обнаружена необходимая информация.
  • Создать / получить JAXBContext основанный на значении id элемент.
  • Создать UnmarshallerHandler от JAXBContext,
  • Вызов событий в очереди на UnmarshallerHandler,
  • Установить UnmarshallerHandler на XMLReader как ContentHandler,
  • Получите неупорядоченный объект из UnmarshallerHandler,
package forum13397834;

import java.util.*;
import javax.xml.bind.*;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;

public class LookAheadUnmarshallerHandler extends DefaultHandler {

    private XMLReader xmlReader;
    private List<Event> events = new ArrayList<Event>();
    private UnmarshallerHandler unmarshallerHandler;

    public LookAheadUnmarshallerHandler(XMLReader xmlReader) {
        this.xmlReader = xmlReader;
    }

    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        events.add(new StartElement(uri, localName, qName, attributes));
    }

    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        if("id".equals(localName) || "id".equals(qName)) {
            Characters characters = (Characters) events.get(events.size() - 1);
            String value = characters.getString();
            JAXBContext jc;
            try {
                if("1234".equals(value)) {
                    jc = JAXBContext.newInstance(Root1.class);
                } else if("5678".equals(value)) {
                    jc = JAXBContext.newInstance(Root2.class);
                } else {
                    jc = JAXBContext.newInstance(Root3.class);
                }
                unmarshallerHandler = jc.createUnmarshaller().getUnmarshallerHandler();
            } catch(JAXBException e) {
                throw new RuntimeException(e);
            }
            unmarshallerHandler.startDocument();
            for(Event event : events) {
                event.event(unmarshallerHandler);
            }
            unmarshallerHandler.endElement(uri, localName, qName);
            xmlReader.setContentHandler(unmarshallerHandler);
        } else {
            events.add(new EndElement(uri, localName, qName));
        }
    }

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        events.add(new Characters(ch, start, length));
    }

    public Object getResult() throws JAXBException {
        return unmarshallerHandler.getResult();
    }

    private static abstract class Event {

        public abstract void event(ContentHandler contentHandler) throws SAXException; 

    }

    private static class StartElement extends Event {

        private String uri;
        private String localName;
        private String qName;
        private Attributes attributes;

        public StartElement(String uri, String localName, String qName, Attributes attributes) {
            this.uri = uri;
            this.localName = localName;
            this.qName = qName;
            this.attributes = attributes;
        }

        @Override
        public void event(ContentHandler contentHandler) throws SAXException {
            contentHandler.startElement(uri, localName, qName, attributes);
        }

    }

    private static class Characters extends Event {

        private char[] ch;
        private int start;
        private int length;

        public Characters(char[] ch, int start, int length) {
            this.ch = ch;
            this.start = start;
            this.length = length;
        }

        @Override
        public void event(ContentHandler contentHandler) throws SAXException {
            contentHandler.characters(ch, start, length);
        }

        public String getString() {
            return new String(ch, start, length);
        }

    }

    private static class EndElement extends Event {

        private String uri;
        private String localName;
        private String qName;

        public EndElement(String uri, String localName, String qName) {
            this.uri = uri;
            this.localName = localName;
            this.qName = qName;
        }

        @Override
        public void event(ContentHandler contentHandler) throws SAXException {
            contentHandler.endElement(uri, localName, qName);
        }

    }

}

JAVA МОДЕЛЬ

Следующая объектная модель основана на классах, которые вы упоминаете в своем вопросе.

UserA

package forum13397834;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="root")
public class UserA {

}

UserB

package forum13397834;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="root")
public class UserB {

}

UserC

package forum13397834;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="root")
public class UserC {

}

INPUT (input.xml)

Мы будем использовать документ XML из вашего вопроса в качестве входных данных для этого примера.

<root>
    <user>
        <id>1234</id>
    </user>
    <XMLelements>
        ...
    </XMLelements>
</root>

ДЕМО КОД

package forum13397834;

import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        spf.setNamespaceAware(true);
        XMLReader xmlReader = spf.newSAXParser().getXMLReader();

        LookAheadUnmarshallerHandler handler = new LookAheadUnmarshallerHandler(xmlReader);
        xmlReader.setContentHandler(handler);
        xmlReader.parse(new InputSource("src/forum13397834/input.xml"));
        Object object = handler.getResult();
        System.out.println(object.getClass());
    }

}

Выход

class forum13397834.UserA
Другие вопросы по тегам