问题
I have been trying to wrap a set of classes based on Simple XML (Java Serializer) around a RSS Feed. The sample feed is
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>Coding Horror</title>
<link>http://www.codinghorror.com/blog/</link>
<description>programming and human factors - Jeff Atwood</description>
<language>en-us</language>
<lastBuildDate>Wed, 04 May 2011 20:34:18 -0700</lastBuildDate>
<pubDate>Wed, 04 May 2011 20:34:18 -0700</pubDate>
<generator>http://www.typepad.com/</generator>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<image>
<title>Coding Horror</title>
<url>http://www.codinghorror.com/blog/images/coding-horror-official-logo-small.png</url>
<width>100</width>
<height>91</height>
<description>Logo image used with permission of the author. (c) 1993 Steven C. McConnell. All Rights Reserved.</description>
<link>http://www.codinghorror.com/blog/</link>
</image>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/codinghorror" />
</channel>
</rss>
The error that I am getting while running the code is
org.simpleframework.xml.core.PersistenceException: Element 'link' declared twice at line 24
And the error is fair enough because the particular element name occurs twice in the xml but in different ways.
The first link element is here
<link>http://www.codinghorror.com/blog/</link>
Its directly under the Channel tag. And then the next link tag is again under Channel in the following format
<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/codinghorror" />
In Channel.java class I cannot have two variables with the same name link. I tried changing a variable name to blogLink and tried giving name in the Element annotation and Eclipse gave me this error
Change was
@Element("name=link")
Result is
The attribute value is undefined for the annotation Element
I know I am missing something here but I am not able to put my finger on it. I would appreciate any help on this.
UPDATE
Channel Class
@Element(name="link")
@Namespace(reference="http://www.w3.org/2005/Atom",prefix="atom")
private atomlink atomlink;
public atomlink getAtomLink() {
return atomlink;
}
Link Class
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.Root;
@Root(name="link")
@Namespace(reference="http://www.w3.org/2005/Atom",prefix="atom10")
public class atomlink {
@Attribute
private String rel;
public String getRel() {
return rel;
}
}
I have changed the class names and yet it still points to the same error.
回答1:
These are two different elements. They differ by namespace. See how can you map namespaces (if they are supported by that Simple XML at all).
Uh, found it in the doc:
http://simple.sourceforge.net/download/stream/doc/tutorial/tutorial.php#namesoace
@Element(name="link")
private Link link;
@Element(name="link")
@Namespace(reference="http://www.w3.org/2005/Atom")
private AtomLink atomLink;
and so on.
回答2:
Because the link
element appears twice(though they have different namespace), you need to tell link
apart, blew is my whole answer:
1)Rss
bean
package com.example.xyzreader.data.bean;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.NamespaceList;
import org.simpleframework.xml.Root;
import org.simpleframework.xml.Text;
import java.util.List;
/**
* @author zmingchun
* @version 1.0.0 (2017/3/20)
*/
@NamespaceList({
@Namespace(prefix = "dc", reference = "http://purl.org/dc/elements/1.1/"),
@Namespace(prefix = "atom", reference = "http://www.w3.org/2005/Atom"),
@Namespace(prefix = "xhtml", reference = "http://www.w3.org/1999/xhtml"),
@Namespace(prefix = "atom10", reference = "http://www.w3.org/2005/Atom"),
})
@Root(name = "rss" , strict = false)
public class Rss {
@Element(name = "channel")
public ChannelBean channel;
@Attribute
public String version;
@Override
public String toString() {
return "Rss{" +
"channel=" + channel +
", version='" + version + '\'' +
'}';
}
@Root(name = "channel", strict = false)
public static class ChannelBean {
@Element
public String title;
@ElementList(entry = "link", inline = true, required = false)
public List<Link> links;
@Element
public String description;
@Element
public String language;
@Element
public String lastBuildDate;
@Element
public String pubDate;
@Element
public String generator;
@Element
public String docs;
@Element
public ImageBean image;
@Element
public MetaBean meta;
@Override
public String toString() {
return "ChannelBean{" +
"title='" + title + '\'' +
", links=" + links +
", description='" + description + '\'' +
", language='" + language + '\'' +
", lastBuildDate='" + lastBuildDate + '\'' +
", pubDate='" + pubDate + '\'' +
", generator='" + generator + '\'' +
", docs='" + docs + '\'' +
", image=" + image +
", meta=" + meta +
'}';
}
/**
* link bean
*/
static class Link {
@Attribute(required = false)
public String href;
@Attribute(required = false)
public String rel;
@Attribute(name = "type", required = false)
public String contentType;
@Text(required = false)
public String link;
@Override
public String toString() {
return "Link{" +
"href='" + href + '\'' +
", rel='" + rel + '\'' +
", contentType='" + contentType + '\'' +
", link='" + link + '\'' +
'}';
}
}
@Root(name = "image")
public static class ImageBean {
@Element
public String title;
@Element
public String url;
@Element
public String width;
@Element
public String height;
@Element
public String description;
@Element
public String link;
@Override
public String toString() {
return "ImageBean{" +
"title='" + title + '\'' +
", url='" + url + '\'' +
", width='" + width + '\'' +
", height='" + height + '\'' +
", description='" + description + '\'' +
", link='" + link + '\'' +
'}';
}
}
@Root(name = "meta")
public static class MetaBean {
@Attribute(required = false)
public String name;
@Attribute(required = false)
public String content;
@Override
public String toString() {
return "MetaBean{" +
"name='" + name + '\'' +
", content='" + content + '\'' +
'}';
}
}
}
}
2) TestSimpleXmlConvert
method
package com.example.xyzreader.manager;
import android.util.Log;
import com.example.xyzreader.data.bean.Rss;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.convert.AnnotationStrategy;
import org.simpleframework.xml.core.Persister;
import org.simpleframework.xml.strategy.Strategy;
/**
* @author zmingchun
* @version 1.0.0 (2017/3/20)
*/
public class TestSimpleXmlConvert {
/**
* test convert by simple-xml-2.7.1
*/
public static void main(String[] args) {
Strategy strategy = new AnnotationStrategy();
Serializer serializer = new Persister(strategy);
try {
Rss tRss = serializer.read(Rss.class, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<rss xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:atom=\"http://www.w3.org/2005/Atom\" version=\"2.0\">\n" +
"<channel>\n" +
" <title>Coding Horror</title>\n" +
" <link>http://www.codinghorror.com/blog/</link>\n" +
" <description>programming and human factors - Jeff Atwood</description>\n" +
" <language>en-us</language>\n" +
"\n" +
" <lastBuildDate>Wed, 04 May 2011 20:34:18 -0700</lastBuildDate>\n" +
" <pubDate>Wed, 04 May 2011 20:34:18 -0700</pubDate>\n" +
" <generator>http://www.typepad.com/</generator>\n" +
" <docs>http://blogs.law.harvard.edu/tech/rss</docs>\n" +
"\n" +
" <image>\n" +
" <title>Coding Horror</title>\n" +
" <url>http://www.codinghorror.com/blog/images/coding-horror-official-logo-small.png</url>\n" +
" <width>100</width>\n" +
" <height>91</height>\n" +
" <description>Logo image used with permission of the author. (c) 1993 Steven C. McConnell. All Rights Reserved.</description>\n" +
" <link>http://www.codinghorror.com/blog/</link>\n" +
" </image>\n" +
"\n" +
" <xhtml:meta xmlns:xhtml=\"http://www.w3.org/1999/xhtml\" name=\"robots\" content=\"noindex\" /> \n" +
" <atom10:link xmlns:atom10=\"http://www.w3.org/2005/Atom\" rel=\"self\" type=\"application/rss+xml\" href=\"http://feeds.feedburner.com/codinghorror\" /> \n" +
"\n" +
"</channel>\n" +
" </rss>");
Log.e(TestSimpleXmlConvert.class.getSimpleName(), "Convert result:"+ tRss.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
回答3:
The annotation you have listed is not formatted properly.
It should be
@Element(name="link")
If an annotation has a single property named value, it can be assigned without specifying the key. But in this case, the property you are attempting to set is 'name' which has a value of type String.
The issue from the question is that the whole assignment of 'name' was enclosed in parenthesis, thus it was trying to set 'value' to be "name=link", which is why it was blowing up, because the @Element annotation doesn't specify a value property.
回答4:
I have the same problem parsing the xml with content:
<gd:rating average='4.9304347' max='5' min='1' numRaters='230' rel='http://schemas.google.com/g/2005#overall'/><yt:statistics favoriteCount='0' viewCount='43378'/><yt:rating numDislikes='4' numLikes='226'/>
my code is:
@Element(name="rating", required=false)
@Namespace(prefix="gd", reference="http://schemas.google.com/g/2005")
public Rating rating;
@Element(name="rating")
@Namespace(prefix="yt", reference="http://gdata.youtube.com/schemas/2007")
public LikeRating ratingLike;
The error with this is:
org.simpleframework.xml.core.PersistenceException: Duplicate annotation of name 'rating' on field 'ratingLike' public com.devicefms.android.boardgamesreview.beans.VideoXML$VideoEntry$LikeRating com.devicefms.android.boardgamesreview.beans.VideoXML$VideoEntry.ratingLike at org.simpleframework.xml.core.StructureBuilder.process(StructureBuilder.java:258)
回答5:
This is not a fix per-se, but I was able to work around this issue by replacing the 2 @Element entries for <atom:link/> and <link/> in my class with a single @ElementList, and creating an object that would satisfy both Link types. Something like this:
@NamespaceList({
@Namespace(reference="http://www.w3.org/2005/Atom",prefix="atom")
})
public class Channel {
...
@ElementList(entry="link",inline=true,required=false)
public List<Link> links
...
}
public class Link {
@Attribute(required=false)
public String href;
@Attribute(required=false)
public String rel;
@Attribute(name="type",required=false)
public String contentType;
@Text(required=false)
public String link;
}
回答6:
Has this been resolved? Besides Mark's response (of using a collection) is there a proper way of doing this? How would we guard against other fields that weren't turned into collection become collections?
BTW I am working with RSS feeds.
来源:https://stackoverflow.com/questions/5973028/simple-xml-element-declared-twice-error