XStream several node types in signle collection

↘锁芯ラ 提交于 2019-12-25 08:22:01

问题


I'm trying to deserialize such XML document:

<rootelem>
    <elementType1 arg1="..." />
    <elementType1 arg1="..." />
    <elementType1 arg1="..." />
    <elementType2 argA="..." argB="..." />
    <elementType2 argA="..." argB="..." />
    <elementType2 argA="..." argB="..." />
</rootelem>

By default XStream can parse only such form:

<rootelem>
    <list1>
        <elementType1 arg1="..." />
        <elementType1 arg1="..." />
        <elementType1 arg1="..." />
    </list1>

    <list2>
        <elementType2 argA="..." argB="..." />
        <elementType2 argA="..." argB="..." />
        <elementType2 argA="..." argB="..." />
    </list>
</rootelem>

This is because XStream use next format for collections:

<collection>
    <elem .... />
    <elem .... />
    <elem .... />
</collection>

and frame tags are obligatory. Collection can contain only single type nodes. So how can I parse such XML document? Now I've written my own convertor for this but I wonder are there some other ways?


回答1:


I think that Implicit Collections is the solution for you.

http://x-stream.github.io/alias-tutorial.html#implicit

Here is the sample code:

package com.thoughtworks.xstream;

import java.util.ArrayList;
import java.util.List;

public class Test {

    public static void main(String[] args) {

            Blog teamBlog = new Blog(new Author("Guilherme Silveira"));
            teamBlog.add(new Entry("first","My first blog entry."));
            teamBlog.add(new Entry("tutorial",
                    "Today we have developed a nice alias tutorial. Tell your friends! NOW!"));

            XStream xstream = new XStream();
            xstream.alias("blog", Blog.class);
            xstream.alias("entry", Entry.class);

            xstream.addImplicitCollection(Blog.class, "entries");

            System.out.println(xstream.toXML(teamBlog));
    }
}

And the result:

<blog>
  <author>
     <name>Guilherme Silveira</name>
  </author>
  <entry>
     <title>first</title>
     <description>My first blog entry.</description>
  </entry>
  <entry>
     <title>tutorial</title>
     <description>
          Today we have developed a nice alias tutorial. Tell your friends! NOW!
     </description>
  </entry>
</blog>



回答2:


The first thing you need to do is to create POJOs for all your major XML tags. I assume that the example you gave is not the actual XML you need to "unmarshall" (that's XML lingo for deserialization), but I'll roll with it for the sake of giving you an example to work off of ;-).

public class ElementType1
{
    private String arg1;

    public ElementType1()
    {
        setArg1("");
    }

    public String getArg1()
    {
        return arg1;
    }

    public void setArg1(String newArg1)
    {
        arg1 = newArg1;
    }
}

public class ElementType2
{
    private String argA;
    private String argB;

    public ElementType2()
    {
        setArgA("");
        setArgB("");
    }

    public String getArgA()
    {
        return argA;
    }

    public void setArgA(String newArgA)
    {
        argA = newArgA;
    }

    public String getArgB()
    {
        return argB;
    }

    public void setArgB(String newArgB)
    {
        argB = newArgB;
    }
}

public class RootElement
{
    private List<ElementType1> element1s;
    private List<ElementType2> element2s;

    public RootElement()
    {
        setElement1s(new ArrayList<ElementType1>());
        setElement2s(new ArrayList<ElementType2>());
    }

    public List<ElementType1> getElement1s()
    {
        return element1s;
    }

    public void setElement1s(List<ElementType1> newElement1s)
    {
        element1s = newElement1s;
    }

    public List<ElementType2> getElement2s()
    {
        return element2s;
    }

    public void setElement2s(List<ElementType2> newElement2s)
    {
        element2s = newElement2s;
    }   
}

Now that you have your POJOs, using XStream to marshall (serialize) and unmarshall (deserialize) them to and from XML is quite easy.

List<ElementType1> e1 = new ArrayList<ElementType1>();
List<ElementType2> e2 = new ArrayList<ElementType2>();

ElementType1 a, b, c;
a = new ElementType1();
b = new ElementType1();
c = new ElementType1();

a.setArg1("fizz");
b.setArg1("buzz");
c.setArg1("foo");

e1.add(a);
e1.add(b);
e1.add(c);

ElementType2 d, e;
d = new ElementType2();
e = new ElementType2();

d.setArgA("flim");
d.setArgB("flam");
e.setArgA("something");
e.setArgB("blah");

e2.add(d);
e2.add(e);

RootElement rootElem = new RootElement();
rootElem.setElement1s(e1);
rootElem.setElement2s(e2);

XStream xstream = new XStream();
RootElement rootElem = getYourRootElementSomehow();
String rootElementAsXml = xstream.toXML(rootElem);

System.out.println(rootElementAsXml);

This code will now print the following to the console:

<fully.qualified.pkg.name.RootElement>
    <element1s>
        <fully.qualified.pkg.name.ElementType1>
            <arg1>fizz</arg1>
        </fully.qualified.pkg.name.ElementType1>
        <fully.qualified.pkg.name.ElementType1>
            <arg1>buzz</arg1>
        </fully.qualified.pkg.name.ElementType1>
        <fully.qualified.pkg.name.ElementType1>
            <arg1>foo</arg1>
        </fully.qualified.pkg.name.ElementType1>
    </element1s>
    <element2s>
        <fully.qualified.pkg.name.ElementType2>
            <argA>flim</argA>
            <argB>flam</argB>
        </fully.qualified.pkg.name.ElementType2>
        <fully.qualified.pkg.name.ElementType2>
            <argA>something</argA>
            <argB>blah</argB>
        </fully.qualified.pkg.name.ElementType2>
    </element2s>
</fully.qualified.pkg.name.RootElement>

You can then clean up the nasty, fully-qualified package named XML elements by using XStreams versatile "alias" methods, like so:

xstream.alias("elementType1", ElementType1.class);
xstream.alias("elementType2", ElementType2.class);
xstream.alias("rootElement", RootElement.class);
String rootElementAsXml = xstream.toXML(rootElem);

System.out.println(rootElementAsXml);

Which will now print out:

<rootElement>
    <element1s>
        <elementType1>
            <arg1>fizz</arg1>
        </elementType1>
        <elementType1>
            <arg1>buzz</arg1>
        </elementType1>
        <elementType1>
            <arg1>foo</arg1>
        </elementType1>
    </element1s>
    <element2s>
        <elementType2>
            <argA>flim</argA>
            <argB>flam</argB>
        </elementType2>
        <elementType2>
            <argA>something</argA>
            <argB>blah</argB>
        </elementType2>
    </element2s>
</rootElement>

Now I know that in your example, you wanted all the <arg>s to actually be attributes of the <elementType> tags, not child tags themselves. You can use XStream's powerful API to do this for you, however you like. But hopefully this is enough to get you started.

And by the way, turning your XML back into a POJO is just as easy:

RootElement root = (RootElement)xstream.fromXML(rootElementAsXml);

As a rule of thumb, XStream is an "oxmapper" (Object-XML Mapper), and it come pre-built to know how to turn your POJO into meaningful XML and vice versa. You can always override its defaults, but more often then not I have always found myself surprised with how smart its defaults are. Best of luck to you.



来源:https://stackoverflow.com/questions/8096603/xstream-several-node-types-in-signle-collection

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!