如何在编组时向JAXB中的元素添加命名空间属性? [英] How do I add a namespace attribute to an element in JAXB when marshalling?

查看:183
本文介绍了如何在编组时向JAXB中的元素添加命名空间属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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


org.xml.sax。 SAXException:
SimpleDeserializer遇到了一个子
元素,这是不期望的,在
中它尝试
反序列化。


很多的试验和错误后,我追查了问题。事实证明这是有效的:

 <?xml version =1.0encoding =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.0encoding =UTF-8?> 
< BulkDataExchangeRequests xmlns =urn:ebay:apis:eBLBaseComponents>
< Header>
< Version> 583< / Version>
< SiteID> 0< / SiteID>
< / Header>
< AddFixedPriceItemRequest>

区别在于 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
})
公共类AddFixedPriceItemRequestType

更新3:这是BulkDataExchangeRequestsType类的片段。我尝试将 namespace =urn:ebay:apis:eBLBaseComponents投入到AddFixedPriceItemRequest的@XmlElement中,但它没有做任何事情。

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

感谢所有人的帮助。

解决方案

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



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



这些都没有帮助你。我的方法是将JAXB模型封送到DOM对象(使用 DOMResult 传递给 Marshaller ),以及然后看看你是否可以手动调整DOM来强制 xmlns 进入适当位置的文档。然后,您可以将该DOM序列化为XML并发送。



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






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


I'm working with eBay's LMS (Large Merchant Services) and kept running into the error:

org.xml.sax.SAXException: SimpleDeserializer encountered a child element, which is NOT expected, in something it was trying to deserialize.

After alot of trial and error I traced the problem down. It turns out this works:

<?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">

while this (what I've been sending) doesn't:

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

The difference is the xml namespace attribute on the AddFixedPriceItemRequest . All of my XML is currently being marshalled via JAXB and I'm not sure what is the best way to go about adding a second xmlns attribute to a different element in my file.

So that's the question. How do I add an xmlns attribute to another element in JAXB?

UPDATE:

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;
    }
}

Added class definition by request.

UPDATE 2: Edited the above class like so to no effect:

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

UPDATE 3: Here is a snippet of the BulkDataExchangeRequestsType class. I tried throwing a namespace="urn:ebay:apis:eBLBaseComponents" into the @XmlElement for AddFixedPriceItemRequest but it didn't do anything.

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

UPDATE 4: Here's the hideous chunk of code that is updating the xml after marshalling for me. This is currently working although I'm not particulary proud of it.

    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");
        }
    }

Thanks for all the help everyone.

解决方案

As far as I can tell, your XML fragments are semantically identical. The xmlns attribute on the AddFixedPriceItemRequest element is redundant, since it implicitly inherits the namespace of its parent element. JAXB knows this, and so doesn't bother adding the namespace to AddFixedPriceItemRequest - it's just not necessary.

If the ebay server is only working when the AddFixedPriceItemRequest xmlns is present, then it's broken, and is making demands on the input over and above those required by XML and by the schema. If this is indeed the case (which is hard to believe, but possible), then using a Java XML document model like JAXB is going to be a struggle, since that will assume XML is XML is XML. Low-level farting about with which elements get the xmlns declarations is not exposed to the API, since it shouldn't be needed.

None of which is helping you. My approach would be to marshal the JAXB model to a DOM object (using a DOMResult passed to the Marshaller), and then see if you can do some manual tweaking of the DOM to force the xmlns into the document at the appropriate places. You can then serialize that DOM to XML and send that.

You shouldn't have to do this, and I suspect you may be doing something else wrong somewhere; this is more likely than the ebay web service being broken like this.


edit: here's another suggestion, a bit less awful than the JAXB-to-DOM-to-XML solution. If your request XML is reasonable static in structure, with only the numeric/string values changing, then define it as a String template, then replace the values at runtime, and send that. You can then interpret the results using JAXB. I've done this in the oast with web services thyat required very exact namespace prefixes, when persuading the java XML libraries to conform to that was unreasonably hard.

这篇关于如何在编组时向JAXB中的元素添加命名空间属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆