java - Jaxb和内部元素的命名空间

标签 java xml jaxb

我遇到了一个看起来简单但解决起来并不明显的问题。

我有 2 个包,其中的类编码到具有不同命名空间的 xml 中。一个类是其他类的容器。

package namespace1;

@XmlRootElement(name = "container", namespace = "urn:nmsp:container:001.02")
@XmlAccessorType(XmlAccessType.FIELD)
@Getter
@Setter
public class Container {
    @XmlElement(name = "name")
    private String name;

    @XmlElement(name = "messages")
    private List<Message> messages;
}
-------------------------------------------

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Message", propOrder = {
        "document"
})
public class Message {
    @XmlElement(name = "Document", namespace = "urn:iso:std:iso:20022:001", required = true)
    protected Document document;
}
-------------------------------------------

package-info.java
@javax.xml.bind.annotation.XmlSchema(namespace = "urn:nmsp:container:001.02",
        elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
        xmlns = {
                @XmlNs(namespaceURI = "urn:nmsp:container:001.02", prefix = "")
        })
package namespace1;

package namespace2;

@XmlRootElement(name = "document", namespace = "urn:iso:std:iso:20022:001")
@XmlAccessorType(XmlAccessType.FIELD)
public class Document {
    @XmlElement(name = "id")
    private String id;
}

package-info.java
@javax.xml.bind.annotation.XmlSchema(namespace = "urn:iso:std:iso:20022:001",
        elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
        xmlns = {
                @XmlNs(namespaceURI = "urn:iso:std:iso:20022:001", prefix = "")
        })
package namespace2;

我想要得到的是:

<container xmlns="urn:nmsp:container:001.02">
    <name>Hello</name>
    <messages>
        <Document xmlns="urn:iso:std:iso:20022:001">
            <id>ID1</id>
        </Document>
    </messages>
</container>

但是我得到的是:

<container xmlns="urn:nmsp:container:001.02" xmlns:ns2="urn:iso:std:iso:20022:001">
    <name>Hello</name>
    <messages>
        <ns2:Document>
            <ns2:id>ID1</ns2:id>
        </ns2:Document>
    </messages>
</container>

编码代码是:

Container conxml = new Container("Hello");
conxml.setMessages(List.of(new Message(new Document("ID1")))));
JAXBContext jc = JAXBContext.newInstance(Container.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter writer = new StringWriter();
QName _Conxml_QNAME = new QName("urn:nmsp:container:001.02", "container");
JAXBElement<Container> conxmlJAXBElement = new JAXBElement<>(_Conxml_QNAME, Container.class, null, conxml);
marshaller.marshal(conxmlJAXBElement, writer);
System.out.println(writer.toString());

几乎所有解决方案都建议使用 package-info.java 修复它,但实际上没有帮助。 你能给我一个提示我哪里做错了吗?

maven项目链接:JaxbTest.7z

最佳答案

您提供的两个 XML 文件是等效的,您选择的 namespace 声明是一个品味问题。为每个命名空间选择前缀时,会考虑您在 @XmlNs 注释中设置的前缀。但是,至少 JAXB RI 不会在文档中重新定义它们。

如果您想更直接地干预 XML 的生成方式,则需要在 JAXB 和 Writer 之间添加其他组件。例如。您可以使用 StAX 并将您的文档编码到 XMLStreamWriter就像这个(IndentingXMLStreamWriter 来自 TXW2,JAXB RI 的依赖项):

   private static class RedefineNsXmlStreamWriter extends IndentingXMLStreamWriter {
      @Override
      public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
         final String known_prefix = getNamespaceContext().getPrefix(namespaceURI);
         super.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, localName, namespaceURI);
         if (!XMLConstants.DEFAULT_NS_PREFIX.equals(known_prefix)) {
            super.writeNamespace(XMLConstants.DEFAULT_NS_PREFIX, namespaceURI);
         }
      }
      @Override
      public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
         // Ignore it
      }
      public RedefineNsXmlStreamWriter(XMLStreamWriter out) {
         super(out);
      }
   }

然后创建一个能够写入 Writer 并序列化的 XMLStreamWriter:

final XMLStreamWriter xmlWriter = new RedefineNsXmlStreamWriter(XMLOutputFactory.newFactory()//
                                                                                .createXMLStreamWriter(writerCont));
marshallerCont.marshal(conxmlJAXBElement, xmlWriter);

当然,一旦考虑到所有情况,RedefineNsXmlStreamWriter 就会变得更加复杂,但它适用于您的示例。

关于java - Jaxb和内部元素的命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65798207/

相关文章:

java - Guava teSTLib 中 AbstractPackageSanityTests 异常的含义

java - 如何在必要时使用流 JAVA 8 修改某些值来合并两个 POJOS 列表

c++ - 可能是 rapidxml 中的错误 - 但我不确定如何修复

c++ - XML::CanonicalizeXML Perl 包安装在 Windows 上

java - JAXB:类转换异常,但类具有相同的名称

java - 声明数组不工作java

java - 跨多个域的 Tomcat 集成 Windows 身份验证

android - 下载管理器 Android 权限错误 : write external Storage

java - 如何使用 JAXB 跳过某个字段并仅解码该字段的特定成员?

java - 为什么 JAXB 继承在静态类中不起作用