繁体   English   中英

使用SimpleFramework反序列化多个不同的标签(具有相同的名称)

[英]Deserializing multiple different tags (with the same name) with SimpleFramework

我正在使用用于XML序列化/反序列化的简单框架,尽管第一个很容易,但是后者却有问题。 因此,我从服务器收到XML响应,它看起来像这样:

<?xml version="1.0" ?>
<tables>
    <table name="result" a="context" b="name">
            <r a="stuff1" b="blahblah" />
    </table>
    <table name="response" a="error" b="reason">
            <r a="0" b="" />
    </table>
</tables>

是的,它有2个名称为“表”的元素。 问题在于,第一个“表”元素可能具有3个以上的属性,这意味着,我不能只为“表”标签创建通用实体。 因此,我当前的反序列化实体代码如下所示:

@Root(name = "tables", strict = false)
public class Response {
    @Element(name = "table", required = false)
    @Path("//table[@name='result']")
    Result resultTable;

    @Element(name = "table")
    @Path("//table[@name='result']")
    Response responseTable;

    public Result getResultTable() {
        return resultTable;
    }

    public void setResultTable(Result resultTable) {
        this.resultTable = resultTable;
    }

    public Response getResponseTable() {
        return responseTable;
    }

    public void setResponseTable(Response responseTable) {
        this.responseTable = responseTable;
    }
}

不幸的是,它不起作用:我得到一个例外:

org.simpleframework.xml.core.PathException: Path '//[@name='result']' in field 'resultTable'
com.package.Response.resultTable references document root

我尝试了不同的XPath选项,例如简单的通配节点:

@Path("//*[@name='result']")
@Path("*[@name='result']") 

但这也不起作用。 所以,是由于错误的XPath选项或Simple Framework的限制引起的我的错:

使用此类注释时要注意的一件事是,仅支持XPath表达式语法的子集。 例如,元素和属性引用不能从文档的根部获取,仅允许当前上下文中的引用。

然后应该与其他XML反序列化器一起使用吗? 谢谢。

您可以尝试使用inline-list解决此问题。 另一个-我认为更好的解决方案 :对于“如果名称是将结果反序列化为结果,如果将响应反序列化为响应”部分请使用Converter 这听起来比实际要复杂得多!


班级

由于有两个Response类-一个用于tables ,一个作为table ,我将后一个命名为ResponseTable ; ResultTable在您的示例中为Result 我想您有一些软件包来防止这种情况。

对于两个表,都使用Content类对<r ... />元素进行建模。

响应表

@Root
public class ResponseTable // 'Response' in your code
{
    @Attribute(name = "name")
    private String name;
    @Attribute(empty = "a")
    private String a;
    @Attribute(empty = "b")
    private String b;
    @Element(name = "r")
    private Content r;

    // ...
}

结果表

@Root
public class ResultTable // 'Result' in your code
{
    @Attribute(name = "name")
    private String name;
    @Attribute(empty = "a")
    private String a;
    @Attribute(empty = "b")
    private String b;
    @Element(name = "r")
    private Content r;

    // ...
}

内容

@Root()
public class Content
{
    @Attribute(name = "a")
    private String a;
    @Attribute(name = "b")
    private String b;

    // ...
}

响应

接下来是有趣的部分:

@Root(name = "tables", strict = false)
@Convert(Response.ResponseConverter.class)
public class Response
{
    @Element(name = "table")
    private ResultTable resultTable;
    @Element(name = "table2")
    private ResponseTable responeTable;

    // ...

    static class ResponseConverter implements Converter<Response>
    {
        private final Serializer ser = new Persister();


        @Override
        public Response read(InputNode node) throws Exception
        {
            Response resp = new Response();
            InputNode n = node.getNext();

            while( n != null )
            {
                switch( n.getAttribute("name").getValue() )
                {
                    case "result":
                        resp.resultTable = ser.read(ResultTable.class, n);
                        break;
                    case "response":
                        resp.responeTable = ser.read(ResponseTable.class, n);
                        break;
                    default:
                        throw new RuntimeException("Unsupported table: " 
                                + n.getAttribute("name").getValue());
                }

                n = node.getNext();
            }

            return resp;
        }


        @Override
        public void write(OutputNode node, Response value) throws Exception
        {
            // Implement as needed (hint: again use Serializer here)
            throw new UnsupportedOperationException("Not supported yet.");
        }
    }
}

这里会发生什么:

  1. @Convert用于指定一个Converter实现,该实现实现Response类的(反)序列化
  2. 实施ResponseConverter仅用于确定 <table …>…</table>元素的类型 (= Response或Result表)
  3. 对于实际的反Serializer ,使用常规的Serializer -无需手动完成整个工作!

我尚未实现write()部分,但是如您所见,它并不那么困难; 您可以再次使用Serializer来完成主要工作。


总结一下Converter

  • 如果具有属性名称的= response :反序列化为Response
  • 如果表的属性名称= result :将反序列化为Result
  • 否则:抛出执行

这样就可以拥有多个序列化为xml的类,即使它们共享相同的元素名称。


用法

只需注意一件事:对于@Convert ,必须设置AnnotationStrategy

Serializer ser = new Persister(new AnnotationStrategy());
                               //  ^^^^^^^^^^^^^^^^^^^^
final String xml = …

Response response = ser.read(Response.class, xml);
System.out.println(response)

注: 没有必要使用一个AnnotationStrategy你内的战略Converter -只要你不依赖于其他Converter存在。

输出量

(生成的toString()方法)

Response{resultTable=ResultTable{name=result, a=context, b=name, r=Content{a=stuff1, b=blahblah}}, responeTable=ResponseTable{name=response, a=error, b=reason, r=Content{a=0, b=}}}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM