6

我有一个不是自己创建而是从另一方收到的 XSD。所以我不能改变这个XSD,因为我必须确保与对方的兼容性。

使用简单绑定模式的 XJC 2.2 和 JAXB 2.2 我想在一个空的 hello 元素中创建一个根元素。但是当编组时,我得到了很多额外的命名空间废话。在我看来,这似乎是不必要的。(它虽然有效,但要发送更多数据等......)

XSD 根元素:

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

4

2 回答 2

4

问题如下:模式没有为 element 定义类型hello。结果,XJC 生成了一个类型为 的字段Object。这意味着 JAXB 必须在编组期间检测我们正在处理的对象类型。我不确定细节,但我想它会检查运行时类型,然后相应地处理它。因为String- 这是您实际放入该hello字段的内容 - 直接绑定到模式类型(即xs:string),JAXB 将随之而来。到目前为止,一切都很好。

但是 JAXB 正在尝试生成对解组也很有用的 XML。由于模式没有指定类型并且该hello字段是一个对象,因此尝试从 XML 中解组将使 JAXB 猜测它应该将内容实际转换为什么。告诉它如何的一种方法是使用xsi:type属性指定 XML 元素中的类型。该属性属于xsi-bound 命名空间,因此必须声明和绑定前缀。这就是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 元素上指定一些标准模式类型(如字符串或 int)时,它确实有效,但当我实际尝试为转换提供解析和打印方法时,它再次不起作用,所以我将拥有假设这是在模式中未指定类型时发生的 xjc 中的错误。

我希望其他人可以就绑定问题提供建议。否则,我看到的唯一选择是在释放 XJC 之前通过一些 XSLT 转换发送您的模式,以将每个非类型化元素默认设置为字符串。

于 2011-10-28T14:35:59.250 回答
1

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

当 JAXB 遇到一个anyType元素时,它将把它绑定到 type 的属性Object。您输入此属性的值可以是

  • null, 表示省略元素
  • JAXBContext 知道的类型的对象,它将以正常方式编组并xsi:type添加以指示原始类型是什么,或者
  • 表示org.w3c.dom.Element要使用的实际 XML。

所以试试这个:

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"));
于 2012-12-31T16:54:24.007 回答