简体   繁体   English

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

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

I'm using Simple Framework for XML serialization/deserialization stuff and while the first is easy, I have issues with the latter. 我正在使用用于XML序列化/反序列化的简单框架,尽管第一个很容易,但是后者却有问题。 So, I receive XML response from a server and it looks like this: 因此,我从服务器收到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>

Yes, it has 2 elements with name "table". 是的,它有2个名称为“表”的元素。 The catch is that the first "table" element may have more than 3 attributes, which means, I can't just create an universal entity for "table" tag. 问题在于,第一个“表”元素可能具有3个以上的属性,这意味着,我不能只为“表”标签创建通用实体。 So, my current code for deserialized entity looks like this: 因此,我当前的反序列化实体代码如下所示:

@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;
    }
}

Unfortunately, it doesn't work: I get an exception: 不幸的是,它不起作用:我得到一个例外:

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

I tried different XPath options like simply wildcarting nodes: 我尝试了不同的XPath选项,例如简单的通配节点:

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

but this didn't work either. 但这也不起作用。 So, is it my fault due to incorrect XPath options or limitations of Simple Framework: 所以,是由于错误的XPath选项或Simple Framework的限制引起的我的错:

One thing to note when using such annotations, is that only a subset of the XPath expression syntax is supported. 使用此类注释时要注意的一件事是,仅支持XPath表达式语法的子集。 For example, element and attribute references can not be taken from the root of the document, only references within the current context are allowed. 例如,元素和属性引用不能从文档的根部获取,仅允许当前上下文中的引用。

and should I then do it with other XML deserializers? 然后应该与其他XML反序列化器一起使用吗? Thanks. 谢谢。

You could try go workaround this by using an inline-list . 您可以尝试使用inline-list解决此问题。 Another - and to my mind better solution : Use a Converter for the "if name is result deserialize as Result, if response deserialize as response" part. 另一个-我认为更好的解决方案 :对于“如果名称是将结果反序列化为结果,如果将响应反序列化为响应”部分请使用Converter This sounds more complicated than it actually is! 这听起来比实际要复杂得多!


Classes 班级

Since there are two Response classes - one used for tables and one as table , i named the latter one ResponseTable ; 由于有两个Response类-一个用于tables ,一个作为table ,我将后一个命名为ResponseTable ; ResultTable is Result in your example. ResultTable在您的示例中为Result I guess you have some packages instead to prevent this. 我想您有一些软件包来防止这种情况。

For both tables, a class Content is used to model the <r ... /> element. 对于两个表,都使用Content类对<r ... />元素进行建模。

ResponseTable 响应表

@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;

    // ...
}

ResultTable 结果表

@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;

    // ...
}

Content 内容

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

    // ...
}

Response 响应

And here comes the interesting part: 接下来是有趣的部分:

@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.");
        }
    }
}

What happens here: 这里会发生什么:

  1. @Convert is used to specify a Converter implementation which implements (de-)serialization of the Response class @Convert用于指定一个Converter实现,该实现实现Response类的(反)序列化
  2. The implementation ResponseConverter is only used to determine the type (= Response or Result table) of a <table …>…</table> element 实施ResponseConverter仅用于确定 <table …>…</table>元素的类型 (= Response或Result表)
  3. For the actual deserialization a normal Serializer is used - no need to do the whole work manually! 对于实际的反Serializer ,使用常规的Serializer -无需手动完成整个工作!

I haven't implemented the write() part, but as you can see it's not that difficult; 我尚未实现write()部分,但是如您所见,它并不那么困难; you can utilize a Serializer again to do the main work. 您可以再次使用Serializer来完成主要工作。


To sum it up the Converter : 总结一下Converter

  • If Table with Attribute name = response :Deserialize as Response 如果具有属性名称的= response :反序列化为Response
  • If table with Attribute name = result : Deserialize as Result 如果表的属性名称= result :将反序列化为Result
  • Else: Throw an execption 否则:抛出执行

This makes it possible to have multiple classes which serialize to xml, even if they share the same element name. 这样就可以拥有多个序列化为xml的类,即使它们共享相同的元素名称。


Usage 用法

There's just one thing to notice: For @Convert an AnnotationStrategy must be set: 只需注意一件事:对于@Convert ,必须设置AnnotationStrategy

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

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

Note: There's no need to use an AnnotationStrategy strategy within your Converter - as long as you don't rely on another Converter there. 注: 没有必要使用一个AnnotationStrategy你内的战略Converter -只要你不依赖于其他Converter存在。

Output 输出量

(generated toString() methods) (生成的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.

相关问题 使用SimpleFramework反序列化此XML数组 - Deserializing this XML Array with SimpleFramework 在Jackson中反序列化同名但不同类型的属性? - Deserializing attributes of same name but different types in Jackson? 从不同的XML数据集中以相同名称反序列化XML @Element和@ElementList - Deserializing XML @Element and @ElementList with same name from different XML datasets 简单XML反序列化具有相同名称的不同元素类型 - Simple XML deserializing different element types with the same name 树反序列化时的SimpleFramework java.lang.StackOverflowError - Simpleframework java.lang.StackOverflowError on tree deserializing 将多个 XML 标签重命名为不同的名称 - Rename Multiple XML tags to different name 如果使用Simpleframework解析该xml文件时我们具有如下相同的元素名称,该怎么办 - What to do if we have same element name as follows while parsing that xml file using Simpleframework 使用jackson从改造中反序列化json,其中相同的变量名称可以表示两个不同的对象 - Deserializing json from retrofit using jackson where same variable name can represent two different objects simpleframework,将空元素反序列化为空字符串而不是 null - simpleframework, deserializing an empty element to an empty string instead of null 使用DOM中不同级别上具有相同名称的标签解析XML - Parsing XML with tags with same name on different levels in DOM
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM