I need to parse a XML string into objects. I would use SimpleXML for it but i got an error, Duplicate annotation of name 'link' on field 'url' private java.lang.String com.example.rogedormans.xmlreader.XML.Alert.Channel.url
.
An sample XML with the same problem:
<rss........>
<channel>
<title>The Title</title>
<link>http://www.someurl.com</link>
<description>Some description</description>
<atom:link href="http://dunno.com/rss.xml" rel="self" type="application/rss+xml"/>
....
....
</channel>
</rss>
I googled a lot and found This, this and this stackoverflow article but none worked for me...I also read the Simple XML documentation but i can't get it working.
How can i get both of the "link" items into my object? (i think it is something with the namespace, but what?)
An code example would be nice!!!
You can workaround this by implementing a Converter
for the Channel class.
Here's an example for you. It lacks any kind of error checking etc. and is reduced to Channel
class with a single Atom
only. But you'll see how it works.
Channel
with Converter
@Root()
@Convert(Channel.ChannelConverter.class) // Specify the Converter
public class Channel
{
@Element
private String title;
@Element
private String link;
@Element
private String description;
@Namespace(reference = "http://www.w3.org/2005/Atom", prefix = "atom")
@Element()
private AtomLink atomLink;
// Ctor's / getter / setter ...
static class ChannelConverter implements Converter<Channel>
{
@Override
public Channel read(InputNode node) throws Exception
{
Channel channel = new Channel();
InputNode child;
// Iterate over all childs an get their values
while( ( child = node.getNext() ) != null )
{
switch(child.getName())
{
case "title":
channel.setTitle(child.getValue());
break;
case "description":
channel.setDescription(child.getValue());
break;
case "link":
/*
* "link" can be either a <link>...</link> or
* a <atom:link>...</atom:link>
*/
if( child.getPrefix().equals("atom") == true )
{
AtomLink atom = new AtomLink();
atom.setHref(child.getAttribute("href").getValue());
atom.setRel(child.getAttribute("rel").getValue());
atom.setType(child.getAttribute("type").getValue());
channel.setAtomLink(atom);
}
else
{
channel.setLink(child.getValue());
}
break;
default:
throw new RuntimeException("Unknown Element found: " + child);
}
}
return channel;
}
@Override
public void write(OutputNode node, Channel value) throws Exception
{
/*
* TODO: Implement if necessary
*/
throw new UnsupportedOperationException("Not supported yet.");
}
}
@Root
public static class AtomLink
{
@Attribute
private String href;
@Attribute
private String rel;
@Attribute
private String type;
// Ctor's / getter / setter ...
}
}
All inner classes can be implemented as usual classes too. If things are complex to (de-)serialize you can use a Serializer
within the Converter
too.
And finally a demo:
final String xml = " <channel>\n"
+ " <title>The Title</title>\n"
+ " <link>http://www.someurl.com</link>\n"
+ " <description>Some description</description>\n"
+ " <atom:link href=\"http://dunno.com/rss.xml\" rel=\"self\" type=\"application/rss+xml\" xmlns:atom=\"http://www.w3.org/2005/Atom\" />\n"
+ " ....\n"
+ " ....\n"
+ " </channel>\n";
Serializer ser = new Persister(new AnnotationStrategy());
// ^----- Important! -----^
Channel c = ser.read(Channel.class, xml);
System.out.println(c);
Please note that the Converter
requires a Strategy
(see link above for more details); I have used the AnnotationStrategy
since you can simply use @Convert()
then. The xmlns
has to be defined somewhere in your XML, else you'll catch an Exception; I put it into the <atom:link … />
here.
Channel{title=The Title, link=http://www.someurl.com, description=Some description, atomLink=AtomLink{href=http://dunno.com/rss.xml, rel=self, type=application/rss+xml}}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With