首页 > 解决方案 > 如何在 JAXB Unmarshal 中持久化 Element 的 UserData?

问题描述

我将文档解组为对象,如下所示。在此之前,在解析 XML 时,使用 setUserData 来存储每个元素的位置信息。

class MyJaxbAdapter extends XmlAdapter<Object, SubObject> {}
    @Override
    public UnattendComponent unmarshal(Object v) throws Exception {
        Node node = (Node) v; // ElementNSImpl; It's probably a newly created object. Because It is different from the document object given by ownerDocument as SAXSource.
        node.getUserData(...) // return NULL
    }
}

Document document = ...;
unmarshaller.setAdapter(new MyJaxbAdapter());
MyXMLObject object = unmarshaller.unmarshal(new DOMSource(document), MyXMLObject.class).getValue();

但我无法在 XmlAdapter 的解组方法中获取 UserData。有没有办法持久化 UserData?


定位器信息存储在 Element 的属性中,如下所示。

@Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        Element el = document.createElementNS(usedNamespaceUri, qName);
        // ...
        el.setUserData(
            ElementUserData.class.getName(),
            ElementUserData.builder()
               .lineNumber(locator.getLineNumber())
               .columnNumber(locator.getColumnNumber())
            .build(),
        null);
}

我需要上述代码在 XmlAdapter 的解组中存储的定位器信息(UserData)。但是,node作为参数传递给 unmarshal 的用户数据中没有用户数据。


示例代码:

https://github.com/joseph-jclab/jaxb-question-01

标签: jaxb

解决方案


不完全确定这是否是您正在寻找的东西,但将其作为参考提供,这样您可能会有一些想法进一步进行:

示例 XML:

<root>
    <name>Batman</name>
    <year>2008</year>
</root>

根类:

@XmlRootElement(name = "root")
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
    private String name;
    private String year;

    @XmlJavaTypeAdapter(CustomAdapter.class)
    private String after;

    private void afterUnmarshal(Unmarshaller m, Object parent) {
        after = name;
    }
}

自定义适配器类:

public class CustomAdapter extends XmlAdapter<String, String> {
    @Override
    public String unmarshal(String v) throws Exception {
        System.out.println("Within Unmarshal : " + v);
        return null;
    }

    @Override
    public String marshal(String v) throws Exception {
        System.out.println("Within Marshal : " + v);
        return null;
    }
}

示例主类:

public class SampleMain {
    public static void main(String[] args) throws XMLStreamException, JAXBException {
        final InputStream inputStream = Unmarshalling.class.getClassLoader().getResourceAsStream("sample.xml");
        final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
        final Unmarshaller unmarshaller = JAXBContext.newInstance(Root.class).createUnmarshaller();
        unmarshaller.setAdapter(new CustomAdapter());
        final Root root = unmarshaller.unmarshal(xmlStreamReader, Root.class).getValue();
        System.out.println(root.toString());

        Marshaller marshaller = JAXBContext.newInstance(Root.class).createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.marshal(root, System.out);
    }
}

输出:

Root(name=Batman, year=2008, after=Batman)
Within Marshal : Batman
<root>
   <name>Batman</name>
   <year>2008</year>
</root>

推荐阅读