Как избежать ненужных объявлений пространства имен в маршалированном элементе / теге? - PullRequest
6 голосов
/ 28 октября 2011

У меня есть XSD, который не создан самостоятельно, а получен от другой стороны.Поэтому я не могу изменить этот XSD, потому что я должен обеспечить совместимость с другой стороной.

Используя XJC 2.2 и JAXB 2.2 в режиме простой привязки, я хочу создать корневой элемент внутри пустого элемента hello.Но когда я собрал, я получил много лишнего дерьма пространства имен.Что для меня выглядит ненужным.(Хотя это работает, но для передачи данных требуется больше данных ...)

XSD-элемент:

<element name="epp">
        <complexType>
            <choice>
                <element name="greeting" type="epp:greetingType" />
                <element name="hello" />
                <element name="command" type="epp:commandType" />
                <element name="response" type="epp:responseType" />
                <element name="extension" type="epp:extAnyType" />
            </choice>
        </complexType>
    </element>

Java-код:

Epp epp = new Epp(); 
epp.setHello("");

Marshalled Результат:

<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
     <hello xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string"></hello>
</epp>

Предпочтительный результат:

<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<hello />
</epp>

Или:

<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<hello></hello>
</epp>

Есть ли способ сделать это возможным, желательно без изменения XSD или изменения вручную скомпилированного XJCклассы?

Ответы [ 2 ]

4 голосов
/ 28 октября 2011

Проблема заключается в следующем: схема не определяет тип для элемента hello.В результате XJC генерирует поле с типом Object.Это означает, что JAXB должен определить во время сортировки, с каким объектом мы имеем дело.Я не уверен в деталях, но я полагаю, что он проверит тип среды выполнения, а затем решит проблему соответствующим образом.Поскольку String - это то, что вы фактически вводите в поле hello - имеет прямую привязку к типу схемы (а именно xs:string), JAXB собирается пойти с этим.Пока все хорошо.

Но JAXB пытается генерировать XML, который также будет полезен для демаршаллинга.Поскольку в схеме не указан тип, а в поле hello указан объект, попытка разархивировать из XML заставит JAXB догадываться, во что именно он должен превратить содержимое.Один из способов объяснить, как указать тип в элементе XML с помощью атрибута xsi:type.Этот атрибут попадает в пространство имен xsi, поэтому префикс должен быть объявлен и связан.Вот что происходит с xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance".Но это еще не все ... Объявленный xsi:type использует тип в пространстве имен XML-схемы, связанный с префиксом xs, что означает, что THAT также должен быть объявлен!Отсюда xmlns:xs="http://www.w3.org/2001/XMLSchema".

Результат: беспорядок объявлений пространства имен, просто чтобы сказать, кто бы ни использовал XML, он действительно содержит строку.Эту проблему можно решить, добавив строку в качестве типа элемента hello в схему, но это не вариант для вас.

К счастью, вам не повезло.Вы можете настроить привязки, используя внешний файл привязок.Подробности можно найти здесь: http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/2.0/tutorial/doc/JAXBUsing4.html

Как правило, этот файл привязок должен выполнить трюк:

<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
    version="2.1">

    <!-- Bindings for the general schema -->
    <bindings schemaLocation="test.xsd" node="/xs:schema">

        <bindings node="xs:element[@name='epp']">
            <bindings node=".//xs:element[@name='hello']">
                <javaType name="java.lang.String" />
            </bindings>
        </bindings>

    </bindings>

</bindings>

... но когда я пробую xjc с этим, я получаюошибка the compiler was unable to honor this javaType customization.Это работает, когда я задаю некоторый стандартный тип схемы (например, string или int) для элемента hello в схеме, но опять-таки не сработало, когда я на самом деле пытался предоставить методы разбора и печати для преобразования, поэтому я собираюсьпредположить, что это ошибка в xjc, которая возникает, когда в схеме не указан тип.

Я надеюсь, что кто-то другой может дать совет относительно проблемы привязок.В противном случае единственный вариант, который я вижу, - это отправка вашей схемы через какое-то XSLT-преобразование до того, как на нем будет запущен XJC, чтобы установить для каждого нетипизированного элемента значение string по умолчанию.

1 голос
/ 31 декабря 2012

Если в схеме не указан тип элемента, типом по умолчанию является xs:anyType, который является корнем иерархии типов схемы XML (все простые и сложные типы являются подтипами anyType).

Когда JAXB встречает элемент anyType, он связывает его со свойством типа Object.Значение, которое вы вводите в это свойство, может быть

  • null, что означает опускание элемента
  • объекта типа, о котором знает JAXBContext, который будет маршалирован обычным способоми xsi:type, добавленный, чтобы указать, какой был исходный тип, или
  • org.w3c.dom.Element, представляющий фактический используемый XML.

Так попробуйте это:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().newDocument();

epp.setHello(doc.createElementNS("urn:ietf:params:xml:ns:epp-1.0", "hello"));
...