如何用单个Root类兼容JAXB中同一元素的不同命名空间?
问题描述
原有XML Schema(命名空间http://www.something.com/schema/01p00)对应的Root类:
@XmlRootElement(name = "Root", namespace = "http://www.something.com/schema/01p00") @XmlAccessorType(XmlAccessType.FIELD) public class Root{ // 类内容 }
现在Schema更新为新命名空间http://www.something.com/schema/01p01,但Root元素结构未变。需要用同一个Root类兼容两个命名空间,尝试过package-info配置但未生效:
@javax.xml.bind.annotation.XmlSchema( namespace = "http://www.something.com/schema/01p00", xmlns = { @javax.xml.bind.annotation.XmlNs(prefix = "a", namespaceURI = "http://www.something.com/schema/01p00"), @javax.xml.bind.annotation.XmlNs(prefix = "b", namespaceURI = "http://www.something.com/schema/01p01") }, elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED, attributeFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED ) package schema.package;
解决方案
方法1:添加多个@XmlRootElement注解
JAXB允许在同一个类上声明多个@XmlRootElement,分别对应不同命名空间,既能兼容旧命名空间,也能支持新命名空间:
@XmlRootElement(name = "Root", namespace = "http://www.something.com/schema/01p00") @XmlRootElement(name = "Root", namespace = "http://www.something.com/schema/01p01") @XmlAccessorType(XmlAccessType.FIELD) public class Root { // 类内容保持不变 }
注意:name属性要严格匹配XML中的元素名(区分大小写),确保和新旧Schema中的<a:root>/<b:root>一致。
方法2:解组时自定义命名空间上下文
如果主要处理XML转对象(解组),可以通过自定义NamespaceContext让Unmarshaller识别两个命名空间:
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); // 设置自定义命名空间上下文 unmarshaller.setProperty("jaxb.namespace.context", new NamespaceContext() { @Override public String getNamespaceURI(String prefix) { switch (prefix) { case "a": return "http://www.something.com/schema/01p00"; case "b": return "http://www.something.com/schema/01p01"; default: return XMLConstants.NULL_NS_URI; } } @Override public String getPrefix(String namespaceURI) { switch (namespaceURI) { case "http://www.something.com/schema/01p00": return "a"; case "http://www.something.com/schema/01p01": return "b"; default: return null; } } @Override public Iterator<String> getPrefixes(String namespaceURI) { List<String> prefixes = new ArrayList<>(); if ("http://www.something.com/schema/01p00".equals(namespaceURI)) { prefixes.add("a"); } else if ("http://www.something.com/schema/01p01".equals(namespaceURI)) { prefixes.add("b"); } return prefixes.iterator(); } }); // 执行解组操作 Root root = (Root) unmarshaller.unmarshal(xmlSource);
方法3:修正package-info配置(配合类注解)
如果希望通过package层面统一管理命名空间,需要去掉类上的namespace属性,让类继承package的默认命名空间,但这种方式无法直接支持两个命名空间,通常还是需要结合方法1的多@XmlRootElement注解来实现兼容。
内容的提问来源于stack exchange,提问作者user3052078
相关产品推荐
相关产品推荐

