如何在编组的元素/标记中避免不必要的名称空间声明



我有一个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("");

编组的结果:

<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编译类?

问题如下:模式没有为元素hello定义类型。因此,XJC生成一个类型为Object的字段。这意味着JAXB必须在编组期间检测我们正在处理的对象类型。我不确定细节,但我想它会检查运行时类型,然后相应地处理它。由于String—这是您实际放入hello字段中的内容—与模式类型(即xs:string)有直接绑定,JAXB将使用它。到目前为止,一切顺利。

但是JAXB正在尝试生成对解组也有用的XML。由于模式没有指定类型,并且hello字段是一个对象,因此尝试从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的人它实际上包含一个字符串。这可以通过在模式中添加string作为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转换发送模式,以便在默认情况下将每个非类型化元素设置为字符串。

当模式没有为元素指定类型时,默认类型是xs:anyType,它是XML模式类型层次结构的根(所有简单和复杂类型都是anyType的子类型)。

当JAXB遇到anyType元素时,它将把它绑定到Object类型的属性。这个属性的值可以是

  • null,表示省略
  • 元素
  • 是JAXBContext所知道的类型的对象,将以正常方式对其进行封送,并添加xsi:type以指示原始类型,或者
  • 表示实际使用的XML的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"));

最新更新