命名空间前缀处理
相信大名鼎鼎的ns2,nsXX让很多人非常头疼类似下面这样的
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
11
A1
22
B2
@XmlSchema( xmlns = { @XmlNs(namespaceURI = "http://www.lzrabbit.cn", prefix = "rabbit"), @XmlNs(namespaceURI = "http://www.cnblogs.com", prefix = "blog")})packagecn.lzrabbit;importjavax.xml.bind.annotation.XmlSchema;import javax.xml.bind.annotation.XmlNs;
ClassA如下
packagecn.lzrabbit;import javax.xml.bind.annotation.*;
@XmlRootElement(namespace="http://www.lzrabbit.cn")
@XmlAccessorType(XmlAccessType.FIELD)public classClassA {private intclassAId;
@XmlElement(name="ClassAName")privateString classAName;privateClassB classB;public intgetClassAId() {returnclassAId;
}public void setClassAId(intclassAId) {this.classAId =classAId;
}publicString getClassAName() {returnclassAName;
}public voidsetClassAName(String classAName) {this.classAName =classAName;
}publicClassB getClassB() {returnclassB;
}public voidsetClassB(ClassB classB) {this.classB =classB;
}
}View Code
序列化结果如下,可以看到已经按照我们所预期的修改了命名空间前缀,[email protected]ootElement(namespace="http://www.lzrabbit.cn")注解时指定的namespace必须和package-info.java定义的前缀一致,否则还是会生成nsXX这样的前缀
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
11
A1
22
B2
注意事项
1.若jdk版本为1.6的需要需要添加jaxb-core-2.2.7.jar和jaxb-impl-2.2.7.jar两个包的引用,否则即便设置了package-info的XmlSchema注解的xmlns注释也不能生效,若为jdk
1.7的无需添加
2.使用XmlSchema定义的前缀会对整个包生效,无法实现对每个实体类的单独前缀定义,很不灵活,故此不推荐使用此方式
解决方法二(推荐):
同方法一若jdk版本为1.6需要添加jaxb-core-2.2.7.jar和jaxb-impl-2.2.7.jar两个包的引用,不过方法二不需要添加package-info当然也就不需要定义XmlSchema
思路就是实现NamespacePrefixMapper抽象类,并重写getPreferredPrefix方法,看到方法名应该都明白了,对就是在序列化的时候重写获取命名空间前缀方法,为了简洁这里使用类匿名内部类实现的
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", newNamespacePrefixMapper() {
@Overridepublic String getPreferredPrefix(String namespaceUri, String suggestion, booleanrequirePrefix) {if (namespaceUri.equals("http://www.lzrabbit.cn")) return "abc";returnsuggestion;
}
});
如上所示,在序列化时判断namespaceUri也就是我们定义的命名空间,然后返回我们自定义的前缀,其中的suggestion参数就是默认的前缀,有兴趣的话打印下就会发现suggestion就是ns2之类的前缀,把要自定义前缀的命名空间都在这里判断下就可以完全控制自定义前缀了,相对方法一来说可以实现对每个实体类的命名空间前缀控制,采用方法二后的序列化结果:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
11
A1
22
B2
采用方法二后的序列化方法
packagecn.lzrabbit;importjava.io.StringReader;importjava.io.StringWriter;import javax.xml.bind.*;importcom.sun.xml.bind.marshaller.NamespacePrefixMapper;importcom.sun.xml.bind.v2.WellKnownNamespace;public classXmlUtil {public staticString toXML(Object obj) {try{
JAXBContext context=JAXBContext.newInstance(obj.getClass());
Marshaller marshaller=context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING,"UTF-8");// //编码格式
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);//是否格式化生成的xml串
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);//是否省略xm头声明信息
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", newNamespacePrefixMapper() {
@Overridepublic String getPreferredPrefix(String namespaceUri, String suggestion, booleanrequirePrefix) {if (namespaceUri.equals("http://www.lzrabbit.cn")) return "abc";if (namespaceUri.contains("http://www.cnblogs.com")) return "blog";returnsuggestion;
}
});
StringWriter writer= newStringWriter();
marshaller.marshal(obj, writer);returnwriter.toString();
}catch(Exception e) {throw newRuntimeException(e);
}
}
@SuppressWarnings("unchecked")public static T fromXML(String xml, ClassvalueType) {try{
JAXBContext context=JAXBContext.newInstance(valueType);
Unmarshaller unmarshaller=context.createUnmarshaller();return (T) unmarshaller.unmarshal(newStringReader(xml));
}catch(Exception e) {throw newRuntimeException(e.getMessage());
}
}
}View Code