我有一个XSD,它不是自己创建的,而是从另一方收到的。所以我不能改变这个XSD,因为我必须确保与另一方的兼容性。
使用简单绑定模式使用XJC 2.2和JAXB 2.2我想在一个空的hello元素内部创建一个根元素。但是当编组时我得到了很多额外的命名空间废话。哪个对我来说看起来不需要。 (虽然它有效,但发送的数据更多......)
XSD Rootelement:
<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 Result:
<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编译的类?
答案 0 :(得分:4)
问题如下:架构没有为元素hello
定义类型。因此,XJC会生成类型为Object
的字段。这意味着JAXB必须在编组期间检测到我们正在处理的是什么类型的对象。我不确定细节,但我想它会检查运行时类型然后相应地处理它。由于String
- 这是你实际放入hello
字段的内容 - 直接绑定到模式类型(即xs:string
),因此JAXB将使用它。到目前为止,非常好。
但是JAXB正在尝试生成对解组也有用的XML。由于模式没有指定类型而hello
字段是一个Object,因此尝试从XML解组将使JAXB猜测它应该实际将内容转换为什么。告诉它如何使用xsi:type
属性指定XML元素中的类型的一种方法。此属性属于xsi
绑定的命名空间,因此必须声明和绑定前缀。这就是xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
所发生的事情。但这并非全部...声明的xsi:type
使用XML Schema命名空间中的类型,绑定到前缀xs
,这意味着必须声明这一点!因此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
。当我在模式中的hello元素上指定一些标准模式类型(如string或int)时,它确实有效,但当我实际尝试为转换提供解析和打印方法时再次无法工作,所以我会有假设这是xjc中的一个错误,在模式中没有指定类型时发生。
我希望其他人能就绑定问题提出建议。否则,我看到的唯一选择是在释放XJC之前通过某个XSLT转换发送模式,以便默认情况下将每个非类型化元素设置为字符串。
答案 1 :(得分:1)
当架构未指定元素的类型时,默认类型为xs:anyType
,它是XML架构类型层次结构的根(所有简单类型和复杂类型都是anyType
的子类型)。
当JAXB遇到anyType
元素时,它会将其绑定到类型为Object
的属性。您放入此属性的值可以是
null
,意思是省略元素xsi:type
以指示原始类型是什么,或org.w3c.dom.Element
。所以试试这个:
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"));