提问人:worm359 提问时间:1/30/2023 最后编辑:worm359 更新时间:1/30/2023 访问量:200
如何使用JAXB根据XML中的条件解析为不同的类?
How to parse to different classes based on condition in XML using JAXB?
问:
我有一个使用 JAXB 进行 XML 解析的 Java 应用程序。我需要根据另一个标签的值将其中一个子标签解析为不同的 JAXB 类(想想“version”标签,导致 XML 格式略有不同)。
这是我正在解析的 JAXB 类的代码:Request
@XmlRootElement(name = "request")
@XmlAccessorType(XmlAccessType.FIELD)
public class Request {
@XmlElement(name = "fields1")
private List<Field1> fields1;
@XmlElement(name = "problemTag")
@XmlJavaTypeAdapter(value = JavaBeanAdapter.class)
private List<BaseClass> problemTag;
...
以下是我目前所掌握的一些细节:
- 在我的代码中,我有一个接口。它的实现包含与 JAXB 相关的逻辑(编组和解组)。
IXmlProcessor
- 我为我的问题标签写了一个。它增加了使用具有不同 JAXB 上下文的两个附加实例的额外复杂性。
XmlAdapter
IXmlProcessor
- 我宣布这是春豆。
XmlAdapter
- 我在创建 .
XmlAdapter
javax.xml.bind.Unmarshaller
BaseClass
是 XML 的“旧”版本的 JAXB 类,并带有较新版本的附加字段; 当然扩展ExtendingClass
ExtendingClass
BaseClass
因此,我的测试实现中的流程是这样的:
- 叫
IXmlProcessor#read(String xml, Class<Z> clazz)
- 在我的习俗中将被调用。
javax.xml.bind.Unmarshaller#unmarshal
XmlAdapter
- 反过来,将调用它自己的 IXmlProcessor 实例来解析为 或 .
XmlAdapter
String
BaseClass
ExtendingClass
下面是代码示例:
public class JavaBeanAdapter extends XmlAdapter<Object, BaseClass> {
private IXmlProcessor xmlOld;
private IXmlProcessor xmlNew;
//IXmlProcessor, holding JAXBContext with BaseClass
public void setXmlOld(IXmlProcessor xml) {
this.xmlOld = xml;
}
//IXmlProcessor, holding JAXBContext with ExtendingClass
public void setXmlNew(IXmlProcessor xml) {
this.xmlNew = xml;
}
//First, I parse org.w3c.dom.Element back to string.
//Than I can inspect raw XML.
//This is just test solution, obviously too sloppy to be used in prod, just to get an insight to what i want to achieve
@Override
public BaseClass unmarshal(Object v) {
if (v == null) return null;
String rawXmlTag = xmlNew.asStringNonRoot(v, Object.class, ((Element) v).getTagName());
BaseClass req;
if (rawXmlTag.contains("someSPecificTagForNewVersionOfXml")) {
req = xmlNew.read(rawXmlTag, ExtendingClass.class);
} else {
req = xmlOld.read(rawXmlTag, BaseClass.class);
}
return req;
}
@Override
public Object marshal(BaseClass v) throws Exception {
if (v == null) return null;
else if (v instanceof ExtendingClass) return xmlNew.asStringNonRoot((ExtendingClass) v,
ExtendingClass.class, "BaseClass");
else return xmlOld.asStringNonRoot(v, BaseClass.class, "BaseClass");
}
}
然后,我手动将此适配器添加到主实现中的解组器中。
当然,我不满意.
部分实现代码(用于理解那里的内容):IXmlProcessor
rawXmlTag.contains(...)
IXmlProcessor
public <Z> Z read(String xml, Class<Z> clazz) {
try {
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(new StringReader(xml));
return genUnmarshaller(clazz).unmarshal(xmlStreamReader, clazz).getValue();
} catch (Exception e) {
log.error(ExceptionUtils.getStackTrace(e));
throw errorGenerator.throwableRuntime(CommonScoringError.BAD_XML);
}
}
@Override
public <Z> String asStringNonRoot(Z xmlObj, Class<Z> clazz, String rootName) {
try {
StringWriter strWriter = new StringWriter();
Marshaller marshaller = genMarshaller(xmlObj);
QName qName = new QName(null, rootName);
JAXBElement<Z> root = new JAXBElement<Z>(qName, clazz, xmlObj);
marshaller.marshal(root, strWriter);
return strWriter.toString();
} catch (Throwable e) {
log.error("Error serializing object to XML string: {}", ExceptionUtils.getStackTrace(e));
throw new IllegalStateException("cannot serialize object to XML");
}
}
@Override
public <Z> Z read(org.w3c.dom.Document xml, Class<Z> clazz) {
try {
return genUnmarshaller(clazz).unmarshal(xml, clazz).getValue();
} catch (Exception e) {
log.error(ExceptionUtils.getStackTrace(e));
throw errorGenerator.throwableRuntime(CommonScoringError.BAD_XML);
}
}
我的问题如下:
- 是否有任何替代解决方案可以在不添加具有不同 JAXB 上下文的其他实例的情况下解决此问题?如何改进和简化此实现?
IXmlProcessor
- 也许我应该在解组后检查rootObject.version值,然后手动设置/的正确版本。我应该如何精确地获取原始 Xml?
BaseClass
ExtendingClass
BaseClass
ExtendingClass
任何帮助将不胜感激。
我使用 XmlAdapter 手动找出 xml 格式。它解决了问题,但会导致难以理解、可疑的代码。
答: 暂无答案
评论