Подтвердить что ты не робот

Jaxb: как размонтировать xs: любую часть XML-строки?

У меня есть приложение, делающее конверсии 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 и поместить в какой-либо элемент (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

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

4b9b3361

Ответ 1

@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 и развязать его в целевой объект во втором unmarshalling с anothe JAXB-контекстом (который знает ваш класс MyClass). Что-то вроде:

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

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

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

Ответ 2

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

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

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

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

Ответ 3

<xs:any/>

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

<element name="any" type="xs:anyType"/>