使用Retrofit反序列化带有文本和子标签的XML标记 [英] Deserializing an XML tag with text AND subtags using Retrofit

查看:133
本文介绍了使用Retrofit反序列化带有文本和子标签的XML标记的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Retrofit和SimpleXML来解析来自某些公共API的XML响应。我一直在很好地处理所有内容,直到我偶然发现包含自由文本和子标记的XML标记 - 如下例所示:

I'm using Retrofit and SimpleXML in order to parse an XML response from some public API. I've been doing pretty well with all content, till I stumbled upon XML tags that contain both free-text AND sub-tags - as illustrated by the following example:

<a>
   Some free-style text
   <b>Even more text!</b>
</a>

在尝试使用Simple-XML注释进行反序列化时,我有两种方法。请注意,基本上'a'是列表的条目标记:

In an attempt to deserialize using Simple-XML annotations, I've gone two ways. Keep in mind that basically the 'a's are a list of entry tags:

@ElementList(entry = "a", inline = true, required = false) List<A> aList;

A定义如下:

public static class A {
    @Text(required = false) protected String a;
}

这会很好地读取自由文本部分,但是任何反序列化内容的尝试b标签(例如,通过添加 @Element w或w / o @Path 注释成员到类' A'失败了。我查看了SimpleXML文档,显然使用 @Text 存在限制:

This reads the free-text portion well, but any attempt to deserialize the content of the 'b' tag (e.g. by adding @Element w or w/o @Path annotation members to class 'A') has failed. I looked into the SimpleXML documentation and apparently there exists a limitation for using @Text:


管理Text注释使用的规则是每个模式类只能有一个。此外,此注释不能与Element注释一起使用。只有属性注释可以与它一起使用,因为此注释不会在拥有元素中添加任何内容。

The rules that govern the use of the Text annotation are that there can only be one per schema class. Also, this annotation cannot be used with the Element annotation. Only the Attribute annotation can be used with it as this annotation does not add any content within the owning element.



第二种方法,更简单:



The second method, which is more simplistic:

@ElementList(entry = "a", inline = true, required = false) List<String> aList;

然而,'a'标签的内容再次正确反序列化,但是没有办法进入对于'b'子标签的内容。

Yet again, the content of 'a' tags get properly deserialize, but there's no way to reach in for the content of the 'b' sub-tags.

如何使用纯粹的'b'子标签对'a'标签的内容进行反序列化关于JAVA对象的简单XML注释?

How can both the content of 'a' tags be deserialized with their associated 'b' sub-tags using pure Simple-XML annotations over JAVA objects?

推荐答案

虽然这个问题似乎没有引起太多关注,但我正在分享我已经找到了解决这个问题的解决方案 - 也许其他人可能会受益。

Though this question doesn't seem to have attract much attention, I'm sharing a solution that I've found for this problem anyways - perhaps others could benefit.

显然,简单XML框架的制造商已经意识到某些XML不是'适合他们预定义的标准情况(很像我的情况)。因此,他们在序列化/反序列化重写。可以创建自定义转换器类,并使用 @Convert 注释将其应用于特定的XML构造。在自定义转换器中,XML反序列化被缩减为非常类似于标准Java org.w3c.dom 框架的API。

Apparently the makers of the Simple XML framework were aware of the fact that some XML's don't fit into their predefined, standard cases (much like in my case). Therefore, they've added support in serialization/deserialization overriding. One can create a custom converter class and use the @Convert annotation to apply it over specific XML constructs. Within the custom converter, the XML deserialization is 'reduced' to an API very similar to the standard Java org.w3c.dom framework.

为了解决我的问题中引入的问题,可以使用以下代码:

In order to solve the problem introduced in my question, the following code can be used:

// First, declare the 'a' tags in the root class hosting them (this is pretty standard):
@ElementList(entry = "a", inline = true) List<A> aList;

// Second, create and apply a custom converter as described:
@Root
@Convert(CustomConverter.class)
public class A {
    String content = "";

    public String getContent() {
        return content;
    }
}

public class CustomConverter implements Converter<A> {

    @Override
    public A read(InputNode node) throws Exception {
        A a = new A();

        String value = node.getValue();
        if (value != null) {
            a.content = value;
        }

        InputNode nodeB = node.getNext();
        if (nodeB != null) {
            value = nodeB.getValue();
            if (value != null) {
                a.content += value;
            }
        }

        return a;
    }

    @Override
    public void write(OutputNode node, A value) throws Exception {
        // N/A
    }
}

CustomConverter 实质上连接内容直接在'a'下的文本和'b'下的文本到A的内容数据成员。

The CustomConverter in essence concatenates the content of the text directly under the 'a' and the text under 'b' onto A's content data member.

为了完全披露,我还想分享我最终要解决的真正解决方案,这是为了推广问题我在这篇文章中询问过。

In the interest of full disclosure, I'd also like to share the real solution I ended up going for, which was for a generalization of the problem I asked about in this post.

我必须反序列化的匿名'a'标签下的内容实际上是HTML标记的文本。例如:

The content under the anonymous 'a' tag that I had to deserialize was in fact HTML-tagged text. For example:

<a>
If you can't explain it 
<i>simply</i>
, you don't 
<i>
   understand it 
   <b>well enough.</b>
</i>
 -- Albert Einstein
</a>

HTML标签与整体解析XML无关:我真正需要的只是用于'a'下的内容在名为'A'的类下以纯文本反序列化。所以这是我的(递归)转换器:

HTML tags are irrelevant for the parsing of the XML as a whole: All I really needed was for the content under 'a' to be deserialized as plain-text under a class named 'A'. So here's my (recursive) converter:

@Override
public A read(InputNode node) throws Exception {
    final StringBuilder sb = new StringBuilder(1024);
    concatNodesTree(sb, node);

    A a = new A();
    a.content = sb.toString();
    return a;
}

private void concatNodesTree(StringBuilder sb, InputNode root) throws Exception {

    if (root.isElement()) {
        sb.append("<").append(root.getName()).append(">");
    }

    String value = root.getValue();
    if (value != null) {
        sb.append(value);
    }

    InputNode node = root.getNext();
    while (node != null) {
        concatNodesTree(sb, node);

        // Each time a sub-tree is 'over', getValue() will deserialize the potentially upcoming free-text
        value = root.getValue();
        if (value != null) {
            sb.append(value);
        }
        node = root.getNext();
    }

    if (root.isElement()) {
        sb.append("</").append(root.getName()).append(">");
    }
}

注意:在此解决方案中,'a'标签也将被解析为最终的字符串。为避免这样做,可以为根节点发出特殊情况concatNodesTree()方法。

Note: In this solution, the 'a' tag would also be parsed into the final string. To avoid doing that, one can issue a special case concatNodesTree() method for the root node.

这篇关于使用Retrofit反序列化带有文本和子标签的XML标记的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆