我正在使用Simple Framework for 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>
是的,它有两个名为“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选项,比如简单地使用wildcarting节点:
@Path("//*[@name='result']")
@Path("*[@name='result']")
但这也不起作用。因此,由于错误的XPath选项或简单框架的limitations而导致我的错误:
使用此类注释时需要注意的一点是,只支持XPath表达式语法的一个子集。例如,元素和属性引用不能从文档的根目录中获取,只允许在当前上下文中引用。
然后我应该使用其他XML反序列化器吗?感谢。
答案 0 :(得分:1)
您可以使用内联列表尝试解决方法。另一个 - 并且在我看来更好的解决方案:使用Converter
作为&#34;如果名称是结果反序列化为结果,如果响应反序列化为响应&#34; part。这听起来比实际更复杂!
由于有两个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.");
}
}
}
这里会发生什么:
@Convert
用于 指定Converter
实现,该实现实现{de-} Response
类的序列化ResponseConverter
仅用于 确定<table …>…</table>
元素的类型 (=响应或结果表)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=}}}