我遇到了一个看起来简单但解决起来并不明显的问题。
我有 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/