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

2022-09-02 09:18:16

我有一个 JAXB 设置,其中我使用@XmlJavaTypeAdapter将类型的对象替换为仅包含该人的 UUID 类型的对象。这完全可以正常工作。但是,生成的 XML 每次使用时都会重新声明相同的命名空间 ()。虽然这通常是可以的,但感觉不对劲。PersonPersonRefxmlns: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>

想:

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

答案 1

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

marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "");

答案 2

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

使用 JAXB 1.0 编组 XML 文档时,元帅对象(控制编组过程的 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>

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

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

问题在于,自动生成的命名空间前缀(如 ns1、ns2 和 ns3)对用户不友好 - 它们通常不能帮助人们理解封送的 XML。

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

当 JAXBSample 程序首次编组 XML 文档时,它会在不使用类的情况下执行此操作。因此,Marshaller 会自动生成一个命名空间前缀,在本例中为 ns2。NamespacePrefixMapper

   <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
   <ns2:JustAnElement xmlns:ns2="a">
       <foo>true</foo>
   </ns2:JustAnElement>

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

程序完成的第二次封送处理使用如下类:JAXBSampleNamespacePrefixMapper

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

类中的方法返回首选前缀,在本例中,将在封送 XML 的根元素处声明。getPreferredPrefix()PreferredMappermappedNamespacea

   <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
   <mappedNamespacea:JustAnElement xmlns:mappedNamespacea="a">
       <foo>true</foo>
   </mappedNamespacea:JustAnElement>

推荐