Простой XML - 2 элемента, одно и то же имя, другое пространство имен
Мне нужно разобрать строку XML в объекты. Я бы использовал SimpleXML для этого, но я получил ошибку, Duplicate annotation of name 'link' on field 'url' private java.lang.String com.example.rogedormans.xmlreader.XML.Alert.Channel.url
,
Пример XML с той же проблемой:
<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>
Я много гуглил и нашел статью " Эта, эта и эта статья", но ни одна из них не сработала для меня... Я также прочитал документацию по простому XML, но не могу заставить ее работать.
Как я могу получить оба элемента "ссылка" в мой объект? (я думаю, что-то с пространством имен, но что?)
Пример кода был бы хорош!!!
1 ответ
Вы можете обойти это путем реализации Converter
для класса Channel.
Вот пример для вас. Отсутствует какая-либо проверка ошибок и т. Д., И она сводится к Channel
класс с одним Atom
только. Но вы увидите, как это работает.
Учебный класс Channel
с 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 ...
}
}
Все внутренние классы также могут быть реализованы как обычные классы. Если вещи сложны для (де-) сериализации, вы можете использовать Serializer
в пределах Converter
тоже.
использование
И наконец демо:
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);
Обратите внимание, что Converter
требует Strategy
(см. ссылку выше для более подробной информации); Я использовал AnnotationStrategy
так как вы можете просто использовать @Convert()
затем. xmlns
должен быть определен где-то в вашем XML, иначе вы поймаете исключение; Я положил это в <atom:link … />
Вот.
Выход
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}}