提问人:František Slabý 提问时间:11/14/2023 更新时间:11/14/2023 访问量:29
使用类似的包装器解组多个 XML
Unmarshalling multiple XMLs with similar wrapper
问:
我有多个不同的XML具有相似的包装器。例如:
<?xml version="1.0" encoding="UTF-8"?>
<response id="085845">
<class name="vera-pd" version="1.25" revision="1">
<method name="platce-info">
<status>0</status>
<error_msg/>
... method content ...
</method>
</class>
</response>
我想根据内容或属性“name”将它们取消编组到 POJO。这样的事情可能吗?我想避免为每个方法编写不同的 ResponseClass。XML不是我的,它们来自不同的系统,所以我无法使用类型或命名空间。
我尝试使用这样的@XmlElements(类 MethodXX1 和 MethodXX2 覆盖 VeraWSMethod)。它不起作用,因为 unmarshaller 无法确定类并在 @XmlElements中使用最后一个。
@XmlRootElement(name = "class")
public class VeraWSClass {
private String name;
private String version;
private String revision;
private VeraWSMethod method;
@XmlAttribute
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlAttribute
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
@XmlAttribute
public String getRevision() {
return revision;
}
public void setRevision(String revision) {
this.revision = revision;
}
@XmlElements({
@XmlElement(name = "method", type = MethodXX1.class),
@XmlElement(name = "method", type = MethodXX2.class)
})
public VeraWSMethod getMethod() {
return method;
}
public void setMethod(VeraWSMethod method) {
this.method = method;
}
}
答:
是的,可以取消封送包含不同内容的 XML 实例,这些内容由具有不同值的给定属性进行区分。
下面是一个独立的 Maven 演示项目和 zip,它使用这些 JAXB 功能来提供解决方案:
@XmlJavaTypeAdapter(MethodXmlAdapter.class)
- 一个 JAXB 注解,用于指定一个类以提供自定义的 unmarshaller 和 marshaller 方法。MethodXmlAdapter.class
- 在解组方法元素时从 JAXB 接收 DOM元素
。该实例用于将可区分名称读取为 DOM 属性。编组时,JAXB 在适配器中提供要编组的实例,以返回到 DOM 表示。Element
MethodXXN
Element
解组的关键点是 distinguishing 属性可以通过编程方式访问,并且 DOM 元素可以解组为所需的 Java 类型。
Context.mainUnmarshalByName(...)
public static Object mainUnmarshalByName(Element element)
{
Object value = null;
String name = element.getAttribute("name");
switch (name)
{
case "platce-info":
value = mainUnmarshal(element, METHODXX1_CLASS);
break;
case "platce-data":
value = mainUnmarshal(element, METHODXX2_CLASS);
break;
default:
value = element;
break;
}
return value;
}
封送的关键点是,可以使用声明的 QName 将不同的实例封送到一个方法元素,无论是否带有命名空间。MethodXXN
@SuppressWarnings({ "rawtypes", "unchecked" })
public static Object mainWrapAsMethod(Object value)
{
Object wrap = null;
if ( value != null )
{
if ( isJAXBElement(value) )
value = ((JAXBElement) value).getValue();
if ( METHODXX1_CLASS.equals(value.getClass()) )
wrap = new JAXBElement(METHOD_QNAME, METHODXX1_CLASS, value);
else if ( METHODXX2_CLASS.equals(value.getClass()) )
wrap = new JAXBElement(METHOD_QNAME, METHODXX2_CLASS, value);
}
return wrap;
}
实现
样本项目使用 HiSrc HigherJAXB Maven 插件和 HiSrc BasicJAXB 中的 XJC 插件生成 JAXB 类。XML 架构将类型定义为包含公共属性和元素的子类型。MethodXXN
MethodBase
XJC 从 platce.xsd 生成的类
org
└── example
└── platce
├── MethodBase.java
├── MethodXX1.java
├── MethodXX2.java
├── ObjectFactory.java
├── Response.java
└── VeraWSClass.java
platce.xsd 架构定义了用于保存 any 元素的类型;但是,HiSrc HigherJAXB Maven 插件使用 HiSrc BasicJAXB 定制 XJC 插件和 HiSrc HyperJAXB Annox 注释 XJC 插件,使用单独的配置文件 VeraWSClass.any.xml 添加 和 注释。 VeraWSClass
@XmlAnyElement
@XmlJavaTypeAdapter
执行
对于演示,您可以使用以下命令运行测试和/或应用程序:
mvn -Ptest clean test
mvn -Pexec compile exec:java -Dexec.args="src/test/samples/response01.xml"
mvn -Pexec compile exec:java -Dexec.args="src/test/samples/response02.xml"
免責聲明:我是分叉的 HiSrc BasicJAXB、HiSrc HigherJAXB 和 HiSrc HyperJAXB Annox 项目的维护者。
评论