2012-03-13 3 views
20

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

Где-то глубоко в моей схеме, у меня есть возможность ввести «ЛЮБОЙ» 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 

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

+0

Благодаря хорошему вкладу в этот домен мне удалось это решить. Один из способов, я застрял с моим узлом «Дом». Просто добавьте простой синтаксический анализ XML, чтобы получить dom из строки. В другом случае я прибегал к работе с XML в пространстве DOM (XPATH), так как он фактически спас меня от некоторых переключений времени и контекста. XPATH на самом деле действительно хорош, чтобы снизить сложность кода. –

ответ

37

@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()); 

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

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

+2

Этот ответ был спасателем жизни. Излишне говорить, что я его поддержал, мне просто жаль, что я не могу сделать это дважды. Отличное объяснение плюс хорошее решение - спасибо, lexicore! – quantum

+2

@Quantum Добро пожаловать. Спасать жизнь просто стало немного легче. :) – lexicore

+0

@lexicore Итак, если XmlAnyElement установлен в false/omitted, он оставит его как объект DOM? –

0
<xs:any/> 

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

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

Я думаю, что вам нужен XSDs для этого «любых» частей и классов для них.

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

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

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

+0

Спасибо за ваш ответ. Однако я никогда не узнаю точное содержание этого «любого» сообщения, и я не хочу знать. Я просто хочу иметь возможность обрабатывать его как кусок. –

+0

Руководство, связанное с предоставлением некоторых хороших подробных знаний в этом домене. –

Смежные вопросы