[英]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! 这听起来比实际要复杂得多!
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 ... />
元素进行建模。
@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;
// ...
}
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: 这里会发生什么:
@Convert
is used to specify a Converter
implementation which implements (de-)serialization of the Response
class @Convert
用于指定一个Converter
实现,该实现实现Response
类的(反)序列化 ResponseConverter
is only used to determine the type (= Response or Result table) of a <table …>…</table>
element ResponseConverter
仅用于确定 <table …>…</table>
元素的类型 (= Response或Result表) 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
来完成主要工作。
Converter
: Converter
: Response
Response
Result
Result
This makes it possible to have multiple classes which serialize to xml, even if they share the same element name. 这样就可以拥有多个序列化为xml的类,即使它们共享相同的元素名称。
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.