在编组时如何向JAXB中的元素添加命名空间属性?

时间:2009-11-17 19:06:44

标签: java xml jaxb xml-namespaces ebay

我正在使用eBay的LMS(大型商户服务)并一直遇到错误:

  

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>

区别在于AddFixedPriceItemRequest上的xml名称空间属性。我的所有XML目前都是通过JAXB编组的,我不确定将第二个xmlns属性添加到文件中的其他元素的最佳方法是什么。

这就是问题所在。如何在JAXB中向另一个元素添加xmlns属性?

更新:

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类的片段。我尝试在@XmlElement中为AddFixedPriceItemRequest抛出namespace="urn:ebay:apis:eBLBaseComponents",但它没有做任何事情。

@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 个答案:

答案 0 :(得分:5)

据我所知,您的XML片段在语义上是相同的。 xmlns元素上的AddFixedPriceItemRequest属性是多余的,因为它隐式继承了其父元素的命名空间。 JAXB知道这一点,所以不打算将命名空间添加到AddFixedPriceItemRequest - 它只是没有必要。

如果ebay服务器仅在AddFixedPriceItemRequest xmlns存在时工作,那么它就会被破坏,并且对输入的要求超出了XML和模式所要求的要求。如果情况确实如此(很难相信,但可能),那么使用像JAXB这样的Java XML文档模型将会很困难,因为这将假设XML是XML就是XML。关于哪些元素获得xmlns声明的低级放弃不会暴露给API,因为它不应该被需要。

这些都没有帮助你。我的方法是将JAXB模型封送到DOM对象(使用传递给DOMResult的{​​{1}}),然后查看是否可以对DOM进行一些手动调整以强制{{1在适当的地方进入文件。然后,您可以将该DOM序列化为XML并发送它。

你不应该这样做,我怀疑你可能在某处做了别的错事;这比ebay网络服务更容易被破坏。


编辑:这是另一个建议,比JAXB-to-DOM-to-XML解决方案更糟糕。如果您的请求XML在结构上是合理的静态,只更改了数字/字符串值,则将其定义为String模板,然后在运行时替换值,并发送它。然后,您可以使用JAXB解释结果。我已经在网络服务中完成了这项工作,因为当说服java XML库符合这种方法时,必须使用非常精确的命名空间前缀。

答案 1 :(得分:4)

检查生成的分类中的字段是否缺少@XmlElement注释,如果存在则缺少命名空间属性。必须存在这两个,以便为封送的xml中的每个元素获取名称空间前缀。

答案 2 :(得分:3)

尝试使用类注释

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

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

属性注释,如果您只想在某些特定情况下指定命名空间