Как добавить атрибут пространства имен к элементу в JAXB при сортировке? - PullRequest
4 голосов
/ 17 ноября 2009

Я работаю с eBay LMS (Large Merchant Services) и продолжаю сталкиваться с ошибкой:

org.xml.sax.SAXException: SimpleDeserializer встретил ребенка элемент, который НЕ ожидается, в что-то пыталось десериализации.

После много проб и ошибок я обнаружил проблему. Оказывается, это работает:

<?xml version="1.0" encoding="UTF-8"?>
<BulkDataExchangeRequests xmlns="urn:ebay:apis:eBLBaseComponents">
  <Header>
    <Version>583</Version>
    <SiteID>0</SiteID>
  </Header>
  <AddFixedPriceItemRequest xmlns="urn:ebay:apis:eBLBaseComponents">

пока это (то, что я отправляю) не делает:

<?xml version="1.0" encoding="UTF-8"?>
<BulkDataExchangeRequests xmlns="urn:ebay:apis:eBLBaseComponents">
  <Header>
    <Version>583</Version>
    <SiteID>0</SiteID>
  </Header>
  <AddFixedPriceItemRequest>

Разница заключается в атрибуте пространства имен xml в AddFixedPriceItemRequest. Весь мой XML в настоящее время маршалируется через JAXB, и я не уверен, как лучше добавить второй атрибут xmlns к другому элементу в моем файле.

Так вот в чем вопрос. Как добавить атрибут xmlns к другому элементу в JAXB?

ОБНОВЛЕНИЕ:

package ebay.apis.eblbasecomponents;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "AddFixedPriceItemRequestType", propOrder = {
    "item"
})
public class AddFixedPriceItemRequestType
    extends AbstractRequestType
{

    @XmlElement(name = "Item")
    protected ItemType item;

    public ItemType getItem() {
        return item;
    }

    public void setItem(ItemType value) {
        this.item = value;
    }
}

Добавлено определение класса по запросу.

ОБНОВЛЕНИЕ 2: отредактировал вышеприведенный класс примерно так, без эффекта:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(namespace = "urn:ebay:apis:eBLBaseComponents",
name = "AddFixedPriceItemRequestType", propOrder = {
    "item"
})
public class AddFixedPriceItemRequestType

ОБНОВЛЕНИЕ 3: Здесь приведен фрагмент класса BulkDataExchangeRequestsType. Я попытался добавить namespace="urn:ebay:apis:eBLBaseComponents" в @XmlElement для AddFixedPriceItemRequest, но ничего не получилось.

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "BulkDataExchangeRequestsType", propOrder = {
    "header",
    "addFixedPriceItemRequest"
})
public class BulkDataExchangeRequestsType {

    @XmlElement(name = "Header")
    protected MerchantDataRequestHeaderType header;
    @XmlElement(name = "AddFixedPriceItemRequest")
    protected List<AddFixedPriceItemRequestType> addFixedPriceItemRequest;

ОБНОВЛЕНИЕ 4: Вот отвратительный кусок кода, который обновляет xml после сортировки для меня. В настоящее время это работает, хотя я не особо горжусь этим.

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware(true);
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.newDocument();
    marshaller.marshal(request, doc);
    NodeList nodes = doc.getChildNodes();
    nodes = nodes.item(0).getChildNodes();
    for(int i = 0; i < nodes.getLength(); i++){
        Node node = nodes.item(i);
        if (!node.getNodeName().equals("Header")){
            ((Element)node).setAttribute("xmlns", "urn:ebay:apis:eBLBaseComponents");
        }
    }

Спасибо всем за помощь.

Ответы [ 3 ]

5 голосов
/ 18 ноября 2009

Насколько я могу судить, ваши XML-фрагменты семантически идентичны. Атрибут xmlns в элементе AddFixedPriceItemRequest является избыточным, поскольку он неявно наследует пространство имен своего родительского элемента. JAXB знает это и поэтому не беспокоится о добавлении пространства имен к AddFixedPriceItemRequest - это просто не нужно.

Если сервер ebay работает только при наличии AddFixedPriceItemRequest xmlns, то он неисправен и предъявляет требования к входным данным сверх тех, которые требуются для XML и схемы. Если это действительно так (в это трудно поверить, но это возможно), то использование модели документа Java XML, такой как JAXB, будет проблемой, поскольку предполагается, что XML - это XML, а XML. Низкоуровневое пердеть о том, какие элементы получают объявления xmlns, не предоставляется API, так как это не нужно.

Ничто из этого не помогает вам. Мой подход заключается в том, чтобы маршалировать модель JAXB в объект DOM (используя DOMResult, переданный в Marshaller), а затем посмотреть, можно ли выполнить ручную настройку DOM, чтобы заставить xmlns в документе в соответствующие места. Затем вы можете сериализовать этот DOM в XML и отправить его.

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


edit: вот еще одно предложение, немного менее ужасное, чем решение JAXB-to-DOM-to-XML. Если ваш XML-запрос является достаточно статичным по структуре, с изменением только числовых / строковых значений, определите его как шаблон String, затем замените значения во время выполнения и отправьте его. Затем вы можете интерпретировать результаты, используя JAXB. Я сделал это в oast с веб-сервисами, которые требовали очень точных префиксов пространства имен, когда убедить библиотеки Java в Java соответствовать этому было неоправданно сложно.

4 голосов
/ 16 февраля 2011

Проверьте, не пропущены ли поля в сгенерированном классе аннотации @XmlElement и, если они есть, отсутствует атрибут пространства имен. Эти два должны присутствовать, чтобы получить префикс пространства имен для каждого элемента в вашем маршалированном xml.

4 голосов
/ 17 ноября 2009

Попробуйте использовать аннотацию класса

@XmlType(namespace="urn:ebay:apis:eBLBaseComponents")

или

@XmlElement(namespace="urn:ebay:apis:eBLBaseComponents")

аннотация свойства, если вы хотите указывать пространство имен только в некоторых определенных случаях

...