【问题标题】:Simple XML - 2 elements, same name different namespace简单的 XML - 2 个元素,同名不同的命名空间
【发布时间】:2016-05-09 19:49:39
【问题描述】:

我需要将 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>

我在 Google 上搜索了很多,发现 This、this 和 this stackoverflow 文章,但没有一个对我有用...我还阅读了 Simple XML documentation,但我无法让它工作。

如何将两个“链接”项都放入我的对象中? (我认为它与命名空间有关,但是什么?)

一个代码示例会很好!!!

【问题讨论】:

    标签: android xml-parsing xml-namespaces simple-framework


    【解决方案1】:

    您可以通过为 Channel 类实现 Converter 来解决此问题。


    这里有一个例子。它缺少任何类型的错误检查等,并且被简化为仅具有单个 Atom 的 Channel 类。但你会看到它是如何工作的。

    类 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 ...
        }
    }
    

    所有内部类也可以像普通类一样实现。如果事情(反)序列化很复杂,您也可以在Converter 中使用Serializer。

    用法

    最后是一个演示:

    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 中的某处定义,否则您将捕获异常;我把它放到&lt;atom:link … /&gt;这里。

    输出

    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}}
    

    【讨论】:

    • 这个弱者我会尝试使用它。第一种方式看起来很棒.. ;-) 当我完成此操作后,我会接受!谢谢
    • 这很好用!但是我不再使用简单的 XML 并创建自己的东西。我以前发现过类似的东西......在这种情况下,我需要编写从简单 XML 到这个的所有内容。 '我不想这样做的第二个原因是因为我有一个非常大的 XML 文件,到时候会得到新的元素。当其他程序员需要更新应用程序以处理新的 XML“格式”时,简单的 XML 看起来比这更容易混淆
    • 您可以在转换器中使用序列化程序来减少工作量。所以你不必自己序列化所有元素。我看到了您的担忧 - 不幸的是,我不确定是否有仅限注释的解决方案。
    猜你喜欢
    • 2012-08-27
    • 1970-01-01
    • 2015-11-11
    • 1970-01-01
    • 1970-01-01
    • 2019-03-01
    • 2019-02-17
    • 1970-01-01
    • 2013-12-04
    相关资源
    最近更新 更多