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

标签 java xpath deserialization simple-framework

我正在使用简单框架进行 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 个名为“table”的元素。问题是第一个“table”元素可能有超过 3 个属性,这意味着我不能只为“table”标签创建一个通用实体。因此,我当前的反序列化实体代码如下所示:

@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 选项不正确还是 limitations简单框架:

One thing to note when using such annotations, is that only a subset of the XPath expression syntax is supported. For example, element and attribute references can not be taken from the root of the document, only references within the current context are allowed.

然后我应该使用其他 XML 反序列化器来执行此操作吗?谢谢。

最佳答案

您可以尝试使用内联列表来解决这个问题。另一个 - 在我看来更好的解决方案:使用 Converter 对于“如果名称是结果反序列化为结果,如果响应反序列化为响应”部分。这听起来比实际上更复杂!

<小时/>

类(class)

因为有两个 Response类 - 一个用于 tables一个为 table ,我将后一个命名为ResponseTable ; ResultTableResult在你的例子中。我猜你有一些软件包来防止这种情况发生。

对于两个表,都有一个类 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> 的类型(= 响应或结果表)元素
  3. 对于实际的反序列化,正常的 Serializer使用 - 无需手动完成整个工作!

我还没有实现write()部分,但正如你所看到的,这并不难;您可以使用 Serializer再次进行主要工作。

<小时/>

总结一下Converter :

  • 如果表具有属性名称 = 响应:反序列化为 Response
  • 如果表具有属性名称 = 结果:反序列化为 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=}}}

关于java - 使用 SimpleFramework 反序列化多个不同的标签(具有相同的名称),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36080359/

相关文章:

java - 如何将 3D 矩阵逆时针旋转 90 度?

.net - 带有命名空间的 XML 的 XPath

perl - 如何序列化和反序列化发送到套接字的哈希值?

java - 从自定义 Jackson Deserializer 中的父节点读取字段

c# - 反序列化动态 JSON 对象

java - Android - inflatinc 类错误 - java.lang.NumberFormatException

java - 如何使用定时器

java - 如何让oracle db支持md5加密?

xml - SwiProlog中的xpath查询中的运算符(operator)预期错误

Java - Html 特殊字符