Jaxb: как разобрать xs: любую часть XML-строки? - PullRequest
22 голосов
/ 13 марта 2012

У меня есть приложение, которое выполняет преобразования XML <-> с использованием Jaxb и автоматически генерирует классы с помощью maven-jaxb2-plugin.

Где-то глубоко в моей схеме у меня есть возможность ввести "ЛЮБОЙ" XML.

Обновление: это лучше описывает мою схему.Некоторый известный XML-код, обертывающий совершенно неизвестную часть («любая»).

<xs:complexType name="MessageType">
  <xs:sequence>
    <xs:element name="XmlAnyPayload" minOccurs="0">
        <xs:complexType>
            <xs:sequence>
                <xs:any namespace="##any"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="OtherElements">
        ....
</xs:sequence>

Это сопоставляет (по jaxb) с таким внутренним классом.

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "any"
})
public static class XmlAnyPayload {

    @XmlAnyElement(lax = true)
    protected Object any;

Когда я отменяю всю структуру, это не проблема.«Любой объект» будет преобразован в org.apache.xerces.dom.ElementNSImpl.Теперь я хочу воссоздать объект Java вручную и перейти к XML.Как мне взять какой-нибудь случайный XML и вставить в элемент any (org.apache.xerces.dom.ElementNSImpl), чтобы иметь возможность создать объект Java?

Кроме того, следующий случай, когда у меня есть этотэлемент как Java, я хочу разобрать эту самую часть (чтобы иметь возможность извлечь строку XML этого элемента).Но это невозможно.Я получаю исключение о корневых элементах.Но аннотировать ElementNSImpl невозможно.

unable to marshal type "com.sun.org.apache.xerces.internal.dom.ElementNSImpl" as an element because it is missing an @XmlRootElement annotation

Есть ли у вас какие-либо предложения по решению этих проблем?

Ответы [ 3 ]

42 голосов
/ 14 марта 2012

@XmlAnyElement(lax = true) означает простым языком что-то вроде:

Уважаемый JAXB! Если у вас есть сопоставление для этого элемента, пожалуйста, распакуйте его в объект Java. Если вы не знаете этот элемент, просто оставьте его как Элемент DOM.

Это именно то, что происходит в вашем случае. Поэтому, если вы действительно хотите разархивировать содержимое этого слабого выражения, предоставьте контексту JAXB сопоставление для элемента, который вы хотите разархивировать. Самый простой способ сделать это - добавить в свой класс @XmlRootElement

@XmlRootElement(name="foo", namespace="urn:bar")
public class MyClass { ... }

Теперь, когда вы создаете свой контекст JAXB, добавьте в него MyClass:

JAXBContext context = JAXBContext.newInstance(A.class, B.class, ..., MyClass.class);

В этом случае, если JAXB встретит элемент {urn:bar}foo вместо этого xs:any, он будет знать, что этот элемент сопоставлен с MyClass и попытается демонтировать MyClass.

Если вы создаете контекст JAXB на основе имени пакета (вы, вероятно, делаете), вы все равно можете добавить к нему свой класс (скажем, com.acme.foo.MyClass). Самый простой способ - создать ресурс com/acme/foo/jaxb.index:

com.acme.foo.MyClass

И добавьте имя вашего пакета в контекстный путь:

JAXBContext context = JAXBContext.newInstance("org.dar.gee.schema:com.acme.foo");

Есть и другие способы с ObjectFactory и т. Д., Но трюк с jaxb.index, вероятно, самый простой.

В качестве альтернативы, вместо того, чтобы демонтировать все за один прогон, вы можете оставить содержимое xs:any как DOM и разархивировать его в целевой объект во втором демаршаллинге с другим контекстом JAXB (который знает ваш класс MyClass). Что-то вроде:

JAXBContext payloadContext = JAXBContext.newInstance(MyClass.class);
payloadContext.createUnmarshaller().unmarshal((Node) myPayload.getAny());

Этот подход иногда лучше, особенно когда у вас есть комбинация схем контейнер / полезная нагрузка, которые относительно независимы. Зависит от случая.

Все сказанное выше относится и к сортировке. Это все аккуратно двунаправленный.

1 голос
/ 13 марта 2012

Я думаю, вам нужны XSD для этой "любой" части, а также для них создаются классы.

Вот еще немного информации:

http://jaxb.java.net/guide/Mapping_of__xs_any___.html

Редактировать: если ваш объект, который вы хотите маршалировать, не имеет аннотации @XmlRootElement (см. Сообщение об ошибке), то я думаю, что вы должны обернуть его JAXBElement.

0 голосов
/ 13 марта 2012
<xs:any/>

требует, чтобы некоторые неинтуитивные вещи были преобразованы в объект Java.Если у вас нет разницы, попробуйте использовать

<element name="any" type="xs:anyType"/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...