Jackson xml反序列化不连续的内联数组

Posted

技术标签:

【中文标题】Jackson xml反序列化不连续的内联数组【英文标题】:Jackson xml deserializing inline array that is not contiguous 【发布时间】:2022-01-22 10:56:53 【问题描述】:

我有一些奇怪的 xml 我正在尝试反序列化为 java 对象

<Operator>
    <Parameter Key="a" Value="1"/>
    <Parameter Key="b" Value="2"/>
    <Parameter Key="c" Value="3"/>
    <StorageParameters Key="x" Value="***"/>
    <Parameter Key="d" Value="4"/>
</Operator>

我只需要收集参数节点作为列表。 我编写了我的java类如下

@JsonIgnoreProperties(ignoreUnknown = true)
public class Operator 
  
    @JacksonXmlProperty(localName="Parameter")
    @JacksonXmlElementWrapper(useWrapping = false)
    private List<Parameter> parameters;

   public Operator() 
       this.parameters = List.of();
   

   public List<Parameter> getParameters() 
        return parameters;
    

    public void setParameters(List<Parameter> parameters) 
        this.parameters = parameters;
    



public class Parameter 
    private String Key;
    private String Value;

    public Parameter() 
        Key = "";
        Value = " ";
    

    public String getKey() 
        return  Key;
    

    public void setKey(String key) 
        Key = key;
    

    public String getValue()  return Value; 

    public void setValue(String value) 
        Value = value;
    


// Driver

JacksonXmlModule module = new JacksonXmlModule();
XmlMapper mapper = new XmlMapper(module);

Operator bean = mapper.readValue(xmlText, classOf[Operator])

当我运行它时,参数列表返回的唯一值是 Key="d" 和 Value="4" 的最后一个参数条目。

这是预期的行为吗?是否有任何注释可以用来获取所有参数键/值对?

谢谢!

【问题讨论】:

【参考方案1】:

这里的问题是 &lt;StorageParameters Key="x" Value="***"/&gt; 标签的存在:jackson 库希望在列表中只反序列化存在的 n &lt;Parameter/&gt; 相等标签,而是找到不同的标签,因此决定将列表解释为不同的属性,因此最后一个 &lt;Parameter Key="d" Value="4"/&gt; 覆盖 Parameter 属性的先前值,然后是奇怪的行为(另一个 StorageParameters 被忽略,导致 JsonIgnoreProperties(ignoreUnknown = true) 类中的 JsonIgnoreProperties(ignoreUnknown = true) 注释)。

为避免这种行为,您可以删除不需要的 StorageParameters 并反序列化您的 xml,解析旧的 xml 并创建一个没有不需要的标签的新 xml,如下所示:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new FileInputStream(xml));
Node node = doc.getElementsByTagName("StorageParameters").item(0);
node.getParentNode().removeChild(node);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
StringWriter writer = new StringWriter();
t.transform(new DOMSource(doc), new StreamResult(writer));
String result = writer.getBuffer().toString();
Operator value = mapper.readValue(result, Operator.class);

您必须在Parameter 中使用JacksonXmlProperty(isAttribute = true) 注释来指示值是属性:

@Data
public class Parameter 

    @JacksonXmlProperty(isAttribute = true)
    private String Key;
    @JacksonXmlProperty(isAttribute = true)
    private String Value;


@Data
public class Operator 

    @JacksonXmlProperty(localName = "Parameter")
    @JacksonXmlElementWrapper(useWrapping = false)
    private List<Parameter> parameters;

【讨论】:

不幸的是我无法控制 xml,所以我必须识别所有中间节点并删除它们。看起来杰克逊可能没有通用的方法。 @sramalingam24 没有自动的方法,如果有多个 xml 标签,另一种方法是 xslt。

以上是关于Jackson xml反序列化不连续的内联数组的主要内容,如果未能解决你的问题,请参考以下文章

怎么将一个数组序列化与反序列化????越详细越好!!!可以加分

Jackson XML - 使用命名空间前缀反序列化 XML

JPA / Jackson - 反序列化时排除字段并在序列化时包含它们

Jackson 反序列化同名的 xml 字段

Jackson XML 反序列化问题

Jackson xml反序列化 - 序列化为一个列表,其中包含任意元素