我可以使用SimpleXML解析结构未知的XML吗?

4
我将使用SimpleXML来解析通信协议中使用的小型XML文件。这一切都很好,但现在我正在实现协议的一个部分,其中包括一种自由形式的XML。

例如,像这样的XML:

<telegram>
  <config>
    <foo>yes</foo>
    <bar>no</bar>
  </config>
</telegram>

将来可能会更改foobar,或者可能会添加一个元素baz,而无需触及解析代码。我想使用Java中的结构访问这些元素,如下所示:

tree.getConfig().get("bar");   // returns "no"

我可以使用SimpleXML来解析它吗?我查看了文档,但没有找到我需要的内容。

2个回答

3

我能使用SimpleXML来解析它吗?

不能直接使用,但是编写转换器可以实现。


@Root(name = "telegram")
@Convert(Telegram.TelegramConverter.class) // Requires AnnotationStrategy
public class Telegram
{
    private Map<String, String> config;


    public String get(String name)
    {
        return config.get(name);
    }

    public Map<String, String> getConfig()
    {
        return config;
    }

    // ...

    @Override
    public String toString()
    {
        return "Telegram{" + "config=" + config + '}';
    }




    static class TelegramConverter implements Converter<Telegram>
    {
        @Override
        public Telegram read(InputNode node) throws Exception
        {
            Telegram t = new Telegram();

            final InputNode config = node.getNext("config");
            t.config = new HashMap<>();

            // Iterate over config's child nodes and put them into the map
            InputNode cfg = config.getNext();

            while( cfg != null )
            {
                t.config.put(cfg.getName(), cfg.getValue());
                cfg = config.getNext();
            }

            return t;
        }

        @Override
        public void write(OutputNode node, Telegram value) throws Exception
        {
            // Implement if you need serialization too
            throw new UnsupportedOperationException("Not supported yet.");
        }

    }
}

使用方法:

final String xml = "<telegram>\n"
        + "  <config>\n"
        + "    <foo>yes</foo>\n"
        + "    <bar>no</bar>\n"
        + "    <baz>maybe</baz>\n" // Some "future element"
        + "  </config>\n"
        + "</telegram>";
/*
 * The AnnotationStrategy is set here since it's
 * necessary for the @Convert annotation
 */
Serializer ser = new Persister(new AnnotationStrategy());
Telegram t = ser.read(Telegram.class, xml);

System.out.println(t);

结果:

Telegram{config={bar=no, foo=yes, baz=maybe}}

0

因为@Convert标记也可以放在字段上,所以我发现比“ollo”的精彩答案更简洁的代码:

    @Root(name = "telegram")
// Requires AnnotationStrategy
public class Telegram {
    @Element
    @Convert(Telegram.ConfigConverter.class)
    private Map<String, String> config;

    public String get(String name) {
        return config.get(name);
    }

    public Map<String, String> getConfig() {
        return config;
    }

    // ...

    @Override
    public String toString() {
        return "Telegram{" + "config=" + config + '}';
    }

    static class ConfigConverter implements Converter<Map<String, String>> {
        @Override
        public Map<String, String> read(final InputNode configNode) throws Exception {
            Map<String, String> map = new HashMap<>();

            // Iterate over config's child nodes and put them into the map
            InputNode cfg = configNode.getNext();

            while (cfg != null) {
                map.put(cfg.getName(), cfg.getValue());
                cfg = configNode.getNext();
            }

            return map;
        }

        @Override
        public void write(OutputNode node, Map<String, String> value) throws Exception {
            // Implement if you need serialization too
            throw new UnsupportedOperationException("Not supported yet.");
        }

    }
}

还有测试:

        final String xml = "<telegram>\n"
            + "  <config>\n"
            + "    <foo>yes</foo>\n"
            + "    <bar>no</bar>\n"
            + "    <baz>maybe</baz>\n" // Some "future element"
            + "  </config>\n"
            + "</telegram>";
    /*
     * The AnnotationStrategy is set here since it's
     * necessary for the @Convert annotation
     */
    Serializer ser = new Persister(new AnnotationStrategy());
    Telegram t = ser.read(Telegram.class, xml);

    assertEquals("yes",t.getConfig().get("foo"));
    assertEquals("no",t.getConfig().get("bar"));
    assertEquals("maybe",t.getConfig().get("baz"));
    assertEquals(3, t.getConfig().size());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接