Java 如何在封送的元素/标记中避免不必要的命名空间声明?

Java 如何在封送的元素/标记中避免不必要的命名空间声明?,java,xml,jaxb,xjc,Java,Xml,Jaxb,Xjc,我有一个XSD,它不是自己创建的,而是从另一方收到的。所以我不能更改这个XSD,因为我必须确保与另一方兼容 使用XJC 2.2和JAXB 2.2,使用简单绑定模式,我想创建一个根元素,其中包含一个空的hello元素。但是当我被编组时,我得到了很多额外的名称空间垃圾。这在我看来是多余的。(虽然可以,但需要发送更多数据…) XSD根元素: <element name="epp"> <complexType> <choice>

我有一个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>
编组结果:

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

或:



是否有任何方法可以实现这一点,最好是不更改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模式名称空间中的一个类型,绑定到前缀
xs
,这意味着也必须声明该类型!因此,
xmlns:xs=”http://www.w3.org/2001/XMLSchema“

结果是:混乱的名称空间声明只是为了告诉使用XML的人它实际上包含字符串。这可以通过在模式中添加string作为hello元素的类型来解决,但这不是您的选项

幸运的是,你并不是完全不走运。可以使用外部绑定文件自定义绑定。详情可在此找到:

通常,此绑定文件应该执行以下操作:

<?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时,我得到了一个错误
,编译器无法执行这个javaType定制。当我在模式中的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"));

介意我编辑问题标题吗?这感觉就像你在问如何生成一个没有内容的元素,但这已经解决了。真正的目标是避免多余的名称空间声明。没问题,这是我在这里的第一个问题…:),是的,目标是去掉那些名称空间decsDid,你尝试不设置Hello值(未运行epp.setHello(“”)?是的,但这只会创建一个空的根元素。因为hello元素不是必需的。根元素中应该至少有一个这样的元素。我已尝试根据需要设置hello,但即使有命令元素,它也将始终存在。因此,另一方的xsd验证无效。我尝试了此方法但不幸的是,当我使用
epp.setHello(“”;
让封送员知道它应该输出元素时,我得到了同样的错误。也许有另一种方法可以设置hello元素,它不会生成字符串。因为XJC将函数编译为
public void setHello(对象值)
使用null就像不设置它一样,封送员不会拾取它。要进行“愚蠢”的猜测,是否存在JAXB“null”对象?:)@PhoenixtheII是否使用了绑定文件?如果是的话,它有效吗?我一直在使用JDK 7分发的XJC,所以以前的版本可能可以使用它。我知道您希望通过为hello元素设置一个空字符串来“强制”它,这是正确的方法。设置null将导致忽略它。但是我们这里的目标是将
Epp
类中的hello字段转换为某种具体类型,因为它是
对象
是导致添加所有xsi:type fluff的原因。啊,好吧,我决定使用“螺旋”模式,因为我最初已经对parties xsd进行了更改,以使其与JAXB兼容(@XmlRootElement-mi)