簡體   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