请考虑以下代码:
Main.java
====
package com.sample;
import com.sample.entity.Customer;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class Main {
public static void main(String[] args) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance(Customer.class);
Customer customer = new Customer();
customer.setId(123);
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m.marshal(customer, System.out);
}
}
Customer.java
====
package com.sample.entity;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Customer {
private long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
package-info.java
====
@XmlSchema(namespace = "http://www.example.org/package", elementFormDefault = XmlNsForm.QUALIFIED)
package com.sample.entity;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.bind.annotation.XmlNsForm;
我希望重用Customer POJO并创建两个不同的命名空间值。所以首先我想打印输出
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer xmlns="http://www.example.org/package">
<id>123</id>
</customer>
像当前代码一样,然后创建第二个xml,其中包含来自同一个pojo的不同主命名空间,如下所示
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer xmlns="http://www.another.org/package">
<id>123</id>
</customer>
或一起删除命名空间
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
<id>123</id>
</customer>
答案 0 :(得分:7)
这是一个很好的问题。
您可以在Jaxb节点级别上工作,而不是在类型级别上工作。 几乎没有任何开销。
关键是从业务逻辑类中创建/访问JAXBElement
(节点级元素),并使用相应的QName
定义自定义它所代表的XML节点。
QName
提供了几种自定义选项,从完全限定的命名空间到根本没有命名空间。唯一需要注意的是,使用不带前缀的命名空间是不可能的。如果您不提供默认命名空间,Jaxb将使用默认命名空间。
示例强>:
QName elaborateQName = new QName("http://www.another.org/package", "customer", "myNs");
QName simpleQName = new QName("customer");
JAXBElement jx1 = new JAXBElement(elaborateQName, customer.getClass(), customer);
JAXBElement jx2 = new JAXBElement(simpleQName, customer.getClass(), customer);
m.marshal(jx1, System.out);
m.marshal(jx2, System.out);
这将产生以下输出:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<myNs:customer xmlns:myNs="http://www.another.org/package">
<id>123</id>
</myNs:customer>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
<id>123</id>
</customer>
使用不带前缀的命名空间是不可能的。尝试使用空前缀或等效XMLConstants.DEFAULT_NS_PREFIX
作为参数的QName将生成一个默认前缀(如 ns1 ):
// QName defaultNs = new QName("http://www.another.org/package", "customer", "");
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:customer xmlns:ns1="http://www.another.org/package">
<id>123</id>
</ns2:customer>
使用 null 作为prefix
的参数会产生异常:
java.lang.IllegalArgumentException: prefix cannot be "null" when creating a QName
at javax.xml.namespace.QName.<init>(QName.java:251)
答案 1 :(得分:3)
如何使用MOXy覆盖root xmlns属性:
EclipseLink MOXy提供了对JAXB编组的轻松自定义,包括更改根元素的默认命名空间。用于覆盖默认命名空间的Object to XML映射( OXM )是:
<?xml version="1.0"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" version="2.5">
<xml-schema element-form-default="QUALIFIED" namespace="http://www.another.org/package"/>
</xml-bindings>
要没有默认命名空间,请改用<xml-schema element-form-default="UNSET"/>
。
MOXy设置:
1)将库添加到项目中:
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>2.6.2</version>
</dependency>
2)在对象模型包中添加jaxb.properties
以启用MOXy的工厂(例如 src/main/resources/com/sample/entity/jaxb.properties
):
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
3)根据您的OXM配置实例化您的上下文(在此示例中为,OXM文件位于 src/main/resources/com/sample/entity/my-oxm.xml
):
Map<String, Source> metadata = Collections.singletonMap("com.sample.entity", new StreamSource(Customer.class.getResourceAsStream("my-oxm.xml")));
Map<String, Object> properties = Collections.singletonMap(JAXBContextProperties.OXM_METADATA_SOURCE, metadata);
JAXBContext jaxbContext = JAXBContext.newInstance(new Class[] {customer.getClass()}, properties);
然后您可以正常使用JAXBContext
上的编组。为要使用的每个不同的OXM文件实例化单独的上下文。
使用MOXy进行其他自定义:
使用MOXy,您可以在不更改对象模型的情况下进一步自定义实体的编组,有效地使您的编组逻辑符合open/closed principle,即使您没有明确的Marshaller
类。例如,如果您需要将Customer
对象编组为Person
,则可以通过添加另一个OXM文件来执行此操作:
<?xml version="1.0"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" version="2.5">
<xml-schema element-form-default="QUALIFIED" namespace="http://www.example.com/person"/>
<java-types>
<java-type name="com.sample.entity.Customer">
<xml-root-element name="person"/>
<java-attributes>
<xml-attribute java-attribute="id" name="personId"/>
<xml-element java-attribute="id" xml-path="someOtherId/text()"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>