JAXB:如何避免xmlns:xsi的重复命名空间定义

sfu*_*ger 20 java xml jaxb

我有一个JAXB设置,我使用@XmlJavaTypeAdapter将类型Person的对象替换为PersonRef仅包含该人的UUID 的类型的对象.这完全没问题.但是,生成的XML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"每次使用时都会重新声明相同的名称空间().虽然这通常没问题,但感觉不对.

如何配置JAXB以在文档的最开头声明xmlns:xsi?我可以手动将名称空间声明添加到根元素吗?

这是我想要实现的一个例子:

当前:

<person uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a">
    <relation type="CHILD"> 
        <to xsi:type="personRef" uuid="56a930c0-5499-467f-8263-c2a9f9ecc5a0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/> 
    </relation> 
    <relation type="CHILD"> 
        <to xsi:type="personRef" uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/> 
    </relation>
    <!-- SNIP: some more relations -->
</person>
Run Code Online (Sandbox Code Playgroud)

通缉:

<person uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <relation type="CHILD"> 
        <to xsi:type="personRef" uuid="56a930c0-5499-467f-8263-c2a9f9ecc5a0"/> 
    </relation> 
    <relation type="CHILD"> 
        <to xsi:type="personRef" uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a"/> 
    </relation>
    <!-- SNIP: some more relations -->
</person>
Run Code Online (Sandbox Code Playgroud)

msp*_*msp 17

不是漂亮,但你可以添加一个空的schemaLocation根元素:

marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "");
Run Code Online (Sandbox Code Playgroud)


Von*_*onC 9

它看起来像JAXB自定义命名空间映射器问题

当您使用JAXB 1.0编组XML文档时,Marshaller对象(一个控制编组过程的JAXB对象)在生成的XML文档中提供名称空间声明.有时Marshaller会生成许多看起来多余的命名空间声明,例如:

   <?xml version="1.0"?>
   <root>
      <ns1:element xmlns:ns1="urn:foo"> ... </ns1:element>
      <ns2:element xmlns:ns2="urn:foo"> ... </ns2:element>
      <ns3:element xmlns:ns3="urn:foo"> ... </ns3:element>
   </root>
Run Code Online (Sandbox Code Playgroud)

JAXB 2.0更改了此行为.如果使用JAXB 2.0(或更高版本)编组XML文档,Marshaller将声明所有静态名称的命名空间统一资源标识符(URI),即在JAXB注释中用作元素或属性名称的URI.

JAXB还可以在XML文档的中间声明其他名称空间,例如,当QName用作属性或元素值的限定名称()需要新的名称空间URI时,或者内容中的文档对象模型(DOM)节点时tree需要一个新的名称空间URI.此行为可能会生成一个XML文档,该文档具有许多带有自动生成的命名空间前缀的命名空间声明.

问题是自动生成的名称空间前缀(如ns1,ns2和ns3)不是用户友好的 - 它们通常无法帮助人们理解编组的XML.

幸运的是,JAXB 2.0(或更高版本)提供了一个名为的服务提供者接口(SPI)com.sun.xml.bind.marshaller.NamespacePrefixMapper,您可以使用该接口为编组指定更有用的名称空间前缀.

当JAXBSample程序第一次编组XML文档时,它会在不使用NamespacePrefixMapper类的情况下完成它.因此,Marshaller会自动生成名称空间前缀,在本例中为ns2.

   <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
   <ns2:JustAnElement xmlns:ns2="a">
       <foo>true</foo>
   </ns2:JustAnElement>
Run Code Online (Sandbox Code Playgroud)

避免命名空间重复的配置示例:

JAXBSample程序完成的第二次编组使用NamespacePrefixMapper如下类:

   NamespacePrefixMapper m = new PreferredMapper();
               marshal(jc, e, m);

   public static class PreferredMapper extends NamespacePrefixMapper {
           @Override
           public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
               return "mappedNamespace" + namespaceUri;
           }
       }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,类中的getPreferredPrefix()方法PreferredMapper返回首选前缀,以mappedNamespacea在编组XML的根元素处声明.

   <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
   <mappedNamespacea:JustAnElement xmlns:mappedNamespacea="a">
       <foo>true</foo>
   </mappedNamespacea:JustAnElement>
Run Code Online (Sandbox Code Playgroud)


小智 6

您可以使用以下代码执行此操作:

marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapper() {
                @Override
                public String[] getPreDeclaredNamespaceUris() {
                    return new String[] { 
                        XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI
                    };
                }

                @Override
                public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
                    if (namespaceUri.equals(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI))
                        return "xsi";
                    if (namespaceUri.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI))
                        return "xs";
                    if (namespaceUri.equals(WellKnownNamespace.XML_MIME_URI))
                        return "xmime";
                    return suggestion;

                }
            });
Run Code Online (Sandbox Code Playgroud)