有没有办法在 JAXB 中为非 collection 元素编组期间添加包装器元素?

Is there a a way to add a wrapper element during the marshalling in JAXB for non collection element?

我正在尝试使用 JAXB 库中的 marshaling 方法创建 XML。对于这种方法,我使用标准 java class 并为其分配注释。我想对 class 中不是 Collections.

中的某些元素进行包装元素

我知道 @XmlElementWrapper 可用于 Collections,但我没有 collection。我有一些元素,我想要一个外部 XML 元素,以便它可以匹配标准 XSD.

我只是想知道是否有办法在某些元素中添加外部 XML 元素,以便创建 XML 与标准 XSD 格式匹配。如果没有直接的方法,那么我可以采用什么替代方法?

正如我们从示例 XML 中看到的那样,carinfo 标签是元素 engineyear 的外部(包装)标签,但是这个 carInfo 标记不存在于 ParentChild class 中。由于这些是标准 classes,我无法修改字段/添加新字段。因此,我想使用 JAXB 处理包装器 XML 标记添加。

以下是输入JSON:

{
   "brand": "Ferari",
   "build": "Italy",
    "engine": "Mercedes",
    "year": "2021"
   
}

以下是我想要的输出 XML:

<?xml version="1.0"?>
<Car>
    <brand>Ferari</brand>
    <build>Italy</build>
    <carinfo>
        <engine>Mercedes</engine>
        <year>2021</year>
    </carinfo>
</Car>

以下是我的 classes:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlTransient
@XmlType(name = "Parent")
public class Parent{
    private String brand;
    private String year;
    
    //Getters and Setters avoided
}

Class 基于 XML 创建:

@XmlRootElement(name = "Car")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Child",propOrder={"brand","engine","build","year"})
public class Child extends Parent{
    private String engine;
    private String build;
    
    //Getter and Setters avoided
}

将创建 XML 的主要 class:我正在使用 Jackson 库从 Json 文件中读取值并创建 XML 基于 Jaxb 注释。

public class Main{

     public static void main(String []args){
        JsonFactory jsonFactory = new JsonFactory();
        JsonParser jsonParser = jsonFactory.createParser(new File(Main.class.getClassLoader().getResource("input.json").toURI()));
        Child eventInfo = jsonParser.readValueAs(Child.class);
        JAXBContext context = JAXBContext.newInstance(Child.class);
        Marshaller mar = context.createMarshaller();
        mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        mar.marshal(eventInfo, System.out);
     }
     
     
}

从我的角度来看,可以在 xml 中包含一个新标签,同时保留原始 类jaxbjavax.xml.transform api。首先是为转换创建一个 xsl 样式表文件,如下所示:

template.xsl

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<Car>
<brand>
<xsl:value-of   select="/Car/brand"/>
</brand>
<build>
<xsl:value-of   select="/Car/build"/>
</build>
<carinfo>
<engine>
<xsl:value-of   select="/Car/engine"/>
</engine>
<year>
<xsl:value-of   select="/Car/year"/>
</year>
</carinfo>
</Car>
</xsl:template>
</xsl:stylesheet>

然后您可以使用集合 a Transformer 并向其传递一个新的 JAXBSource,如下所示:

Child eventInfo = jsonParser.readValueAs(Child.class);
JAXBContext context = JAXBContext.newInstance(Child.class);
           
// Create Transformer
TransformerFactory tf = TransformerFactory.newInstance();
StreamSource xslt = new StreamSource(xslFile);
Transformer transformer = tf.newTransformer(xslt);
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");

//Print to the stdout the desired xml with the new nested tag 
//including the two existing tags
StreamResult result = new StreamResult(System.out);
JAXBSource source = new JAXBSource(context, eventInfo);
transformer.transform(source, result);

最后,我能够使用 Moxy 中的 @XmlPath 获得它,它是基于 Jaxb 的库。您可以将 @XmlPath 用于任何元素,例如集合、非集合、字符串等。我花了很多时间尝试配置和做变通办法,所以在这里发布答案,这样它对某人有用将来他们不会像我一样浪费那么多时间:)

请找到配置 Moxy

的答案

此外,了解如何使用 @XmlPath

获取 XML 的包装元素

您还可以在 EclipseLink 文档中阅读更多相关信息。