使用Retrofit

时间:2015-12-13 20:52:14

标签: java android xml retrofit simple-framework

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

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

为了尝试使用Simple-XML注释进行反序列化,我已经采取了两种方式。请注意,基本上&#39; a 列表的条目标记:

第一个:

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

拥有&#39; A&#39;定义如下:

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

这很好地读取了自由文本部分,但任何尝试反序列化&#39;&#39;标记(例如,通过将@Element w或w / o @Path注释成员添加到类&#39; A&#39;)已失败。我查看了SimpleXML文档,显然使用@Text存在限制:

  

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

第二种方法,更简单:

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

然而,&#39; a&#39;标签得到了正确的反序列化,但是没有办法找到&#39; b&#39;的内容。子标签。

&#39; a&#39;的内容如何?标签与其关联的&#39;&#39;反序列化。使用纯JAVA对象的简单XML注释的子标签?

1 个答案:

答案 0 :(得分:5)

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

显然,Simple XML框架的制造者意识到某些XML不适合他们预定义的标准情况(就像我的情况一样)。因此,他们在serialization/deserialization overriding中添加了支持。可以创建自定义转换器类并使用@Convert注释将其应用于特定的XML构造。在自定义转换器中,XML反序列化被“缩减”为与标准Java org.w3c.dom框架非常相似的API。

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

// 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 content数据成员上。

再迈出一步

为了充分披露,我还想分享我最终要解决的真正解决方案,这是为了概括我在这篇文章中提到的问题。

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

<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”的类下的纯文本。所以这是我的(递归)转换器:

@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()方法。