JAXB:如何将映射编组为value
问题是关于 JAXB Map 编组 - 有很多关于如何将 Map 编组为如下结构的示例:
<map>
<entry>
<key> KEY </key>
<value> VALUE </value>
</entry>
<entry>
<key> KEY2 </key>
<value> VALUE2 </value>
</entry>
<entry>
...
</map>
事实上,这是 JAXB 本身支持的。然而,我需要的是 XML,其中键是元素名称,值是其内容:
<map>
<key> VALUE </key>
<key2> VALUE2 </key2>
...
</map>
我没有按照 JAXB 开发人员推荐的方式成功实现我的地图适配器 (https://jaxb.dev.java.net/guide/Mapping_your_favorite_class.html),根据我的需要,他 - 动态属性名称 :)
有什么解决办法吗?
PS 目前,我必须为我想要编组到 XML 的每个典型键值对集创建一个专用容器类 - 它可以工作,但我必须创建太多这些帮助容器。
The question is about JAXB Map marshalling - there is plenty of examples on how to marhsall a Map into a structure like follows:
<map>
<entry>
<key> KEY </key>
<value> VALUE </value>
</entry>
<entry>
<key> KEY2 </key>
<value> VALUE2 </value>
</entry>
<entry>
...
</map>
In fact, this is natively supported by JAXB. What I need, however, is the XML where key is the element name, and value is its content:
<map>
<key> VALUE </key>
<key2> VALUE2 </key2>
...
</map>
I didn't succeed implementing my Map adapter the way it is recommended by JAXB developers (https://jaxb.dev.java.net/guide/Mapping_your_favorite_class.html), as I need, he - dynamic attribute name :)
Is there any solution for that?
P.S. Currently I have to create a dedicated container class for each typical set of key-value pairs I want to marshall to XML - it works, but I have to create way too many of these helper containers.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
您想要这样做可能有充分的理由,但通常最好避免生成这种类型的 XML。为什么?因为这意味着地图的 XML 元素依赖于地图的运行时内容。由于 XML 通常用作外部接口或接口层,因此这是不可取的。让我解释一下。
Xml 架构 (xsd) 定义 XML 文档的接口契约。除了能够从 XSD 生成代码之外,JAXB 还可以从代码生成 XML 模式。这允许您将通过接口交换的数据限制为 XSD 中定义的预先商定的结构。
在
Map
的默认情况下,生成的 XSD 将限制映射元素包含多个条目元素,每个条目元素必须包含一个xs:string
键和一个xs:string
值。这是一个非常清晰的接口契约。您所描述的是您希望 xml 映射包含其名称将在运行时由映射内容确定的元素。那么生成的 XSD 只能指定映射必须包含编译时类型未知的元素列表。这是定义接口契约时通常应该避免的事情。
为了在这种情况下实现严格的约定,您应该使用枚举类型而不是字符串作为映射的键。例如
,这样您想要成为 XML 中元素的键在编译时就已知,因此 JAXB 应该能够生成一个模式,该模式将映射的元素限制为使用预定义键 KEY 或 KEY2 之一的元素。
另一方面,如果您希望将默认生成的结构简化
为像这样更简单的结构,
您可以使用 MapAdapter 将 Map 转换为 MapElements 数组,如下所示:
There may be a valid reason why you want to do this, but generating this kind of XML is generally best avoided. Why? Because it means that the XML elements of your map are dependent on the runtime contents of your map. And since XML is usually used as an external interface or interface layer this is not desirable. Let me explain.
The Xml Schema (xsd) defines the interface contract of your XML documents. In addition to being able to generate code from the XSD, JAXB can also generate the XML schema for you from the code. This allows you to restrict the data exchanged over the interface to the pre-agreed structures defined in the XSD.
In the default case for a
Map<String, String>
, the generated XSD will restrict the map element to contain multiple entry elements each of which must contain onexs:string
key and onexs:string
value. That's a pretty clear interface contract.What you describe is that you want the xml map to contain elements whose name will be determined by the content of the map at runtime. Then the generated XSD can only specify that the map must contain a list of elements whose type is unknown at compile time. This is something that you should generally avoid when defining an interface contract.
To achieve a strict contract in this case, you should use an enumerated type as the key of the map instead of a String. E.g.
That way the keys which you want to become elements in XML are known at compile time so JAXB should be able to generate a schema that would restrict the elements of map to elements using one of the predefined keys KEY or KEY2.
On the other hand, if you wish to simplify the default generated structure
To something simpler like this
You can use a MapAdapter that converts the Map to an array of MapElements as follows:
提供的代码对我不起作用。
我找到了另一种方式来映射:
MapElements:
MapAdapter:
The rootElement:
我在这个网站中找到了代码:
http://www.developpez.net/forums/ d972324/java/general-java/xml/hashmap-jaxb/
the code provided didn't work for me.
I found another way to Map :
MapElements :
MapAdapter :
The rootElement :
I found the code in this website :
http://www.developpez.net/forums/d972324/java/general-java/xml/hashmap-jaxb/
我仍在研究更好的解决方案,但使用 MOXy JAXB,我已经能够处理以下 XML :
您需要在 Map 属性上使用 @XmlJavaTypeAdapter:
XmlAdapter 的实现如下:
AdpatedMap 类是所有魔法发生的地方,我们将使用 DOM 来表示内容。我们将通过 @XmlAnyElement 和 Object 类型的属性的组合来欺骗 JAXB 介绍处理 DOM:
此解决方案需要 MOXy JAXB 实现。您可以将 JAXB 运行时配置为使用 MOXy 实现,方法是在模型类中添加名为 jaxb.properties 的文件,其中包含以下条目:
以下演示代码可用于验证代码:
I'm still working on a better solution but using MOXy JAXB, I've been able to handle the following XML:
You need to use an @XmlJavaTypeAdapter on your Map property:
The implementation of the XmlAdapter is as follows:
The AdpatedMap class is where all the magic happens, we will use a DOM to represent the content. We will trick JAXB intro dealing with a DOM through the combination of @XmlAnyElement and a property of type Object:
This solution requires the MOXy JAXB implementation. You can configure the JAXB runtime to use the MOXy implementation by adding a file named jaxb.properties in with your model classes with the following entry:
The following demo code can be used to verify the code:
我没有看到任何真正很好地回答这个问题的东西。
我在这里发现了一些效果很好的东西:
使用返回动态元素名称的 JAXB XMLAnyElement 类型样式
我对其进行了一些修改以支持哈希映射树。您可以添加其他集合。
然后实现它:
通过一个简单的 Marshaller 提供如下输出:
I didn't see anything that really answered this very well.
I found something that worked pretty well here:
Use JAXB XMLAnyElement type of style to return dynamic element names
I modified it a bit to support hashmap trees. You could add other collections.
Then to implement it:
Feeding this through a simple Marshaller gives output that looks like this:
我有没有适配器的解决方案。瞬态映射转换为 xml 元素,反之亦然:
我的输出如下:
您可以使用元素名称/值对。我需要属性...
玩得开心!
I have solution without adapter. Transient map converted to xml-elements and vise versa:
My output as espected:
You can use element name/value pair. I need attributes...
Have fun!
(抱歉,无法添加评论)
在 Blaise 上面的回答中,如果您将:更改
为:,
那么这应该摆脱
标记,因此给您:或者:
您还可以将其更改为:
然后您可以完全摆脱
AdaptedMap
,只需将MapAdapter
更改为编组为Document
> 直接反对。我只用编组对此进行了测试,因此可能存在解组问题。我会尝试找时间制作一个完整的示例,并相应地编辑这篇文章。
(Sorry, can't add comments)
In Blaise's answer above, if you change:
to:
then this should get rid of the
<mapProperty>
tag, and so give you:ALTERNATIVELY:
You can also change it to:
and then you can get rid of
AdaptedMap
altogether, and just changeMapAdapter
to marshall to aDocument
object directly. I've only tested this with marshalling, so there may be unmarshalling issues.I'll try and find the time to knock up a full example of this, and edit this post accordingly.
似乎这个问题与另一个问题有点重复,我在一篇文章中收集了一些编组/解组解决方案。您可以在此处查看:使用 JAXB 的动态标签名称。
简而言之:
@xmlAnyElement
的容器类XmlAdapter
可以与@XmlJavaTypeAdapter
配对使用容器类和Map<>之间的转换;
Seems like this question is kind of duplicate with another one, where I've collect some marshal/unmarshal solutions into one post. You may check it here: Dynamic tag names with JAXB.
In short:
@xmlAnyElement
should be createdXmlAdapter
can be used in pair with@XmlJavaTypeAdapter
toconvert between the container class and Map<>;
使用 xml-apis-1.0 时,您可以序列化和反序列化:
使用以下代码:
When using xml-apis-1.0, you can serialize and deserialize this:
Using this code:
Jackson 有一个 XmlMapper 它将支持开箱即用,根本不需要编写任何代码。
这是一个很好的教程
https://www.baeldung.com/jackson-xml-serialization-and-反序列化
Maven依赖项:
用于将
Map
写入xml:将为您提供
我能够通过创建
HashMap
子类来自定义根元素所以现在
将为您提供
Jackson has an XmlMapper which will support this out of the box, no need to write any code at all.
Here's a nice tutorial
https://www.baeldung.com/jackson-xml-serialization-and-deserialization
Maven dependency:
For writing a
Map
to xml:Will give you
I was able to customise the root element by creating a
HashMap
subclassSo now
Will give you
大多数人只提到了
编组
,这里既是编组
又是解组
与Map
Most people have mentioned about only
marshalling
here is bothmarshalling
andunmarshalling
withMap<String,Object>
我找到了最简单的解决方案。
现在它将在您的 xml 输出中生成如下所示:
I found easiest solution.
Now it will generate in you xml output like this: