如何在解析XML时使XStream跳过未映射的标签?

时间:2011-03-21 12:10:04

标签: xml xstream

我有一个大型XML文档,我想将其转换为Java bean。它有很多标签和属性,但我只对少数几个感兴趣。不可思议的是,似乎XStream强制您在该bean中为每个可能在该XML中的标记声明一个属性。有办法解决这个问题吗?

5 个答案:

答案 0 :(得分:17)

初始化XStream,如下所示,忽略bean中未定义的字段。

XStream xstream = new XStream() {
    @Override
    protected MapperWrapper wrapMapper(MapperWrapper next) {
        return new MapperWrapper(next) {
            @Override
            public boolean shouldSerializeMember(Class definedIn, String fieldName) {
                if (definedIn == Object.class) {
                    return false;
                }
                return super.shouldSerializeMember(definedIn, fieldName);
            }
        };
    }
};

答案 1 :(得分:17)

XStream 1.4.5使您可以轻松处理未知标记。对于尚未实现或已被删除且您正在处理旧xml的标记,请使用ignoreUnknownElements()。您还可以指定要忽略的特定标记。


答案 2 :(得分:9)

由于XStream 1.4.5在marshaller声明中使用ignoreEnknownElements()方法就足够了:

XStreamMarshaller marshaller = new XStreamMarshaller();
marshaller.getXStream().ignoreUnknownElements();
...

忽略不必要的元素。

答案 3 :(得分:6)

我今天一直在努力解决这个问题,而且我发现使用return this.realClass(fieldName) != null;并不是(总是)一个有效的解决方案然而实际上有一种方法用于XStream跳过未映射的标签并同时使用隐式集合。

为什么realClass(fieldName)不起作用

实际上是使用

的技巧
try {
    return this.realClass(fieldName) != null;
} catch (Throwable t) {
    return false;
}

的工作原理。它的作用是尝试通过标记名称猜测类型,看它是否成功,如果不成功 - 返回false。所以它会完全跳过像

这样的标签
<someUnknownTag>someContent</someUnknownTag>

但它只能用于当前(!),当某种“不需要”标签碰巧有一个有意义的名称,realClass(fieldName)实际上能够返回不等于null的东西,该标签不会是你的任何ImplicitCollection的成员。在那种情况下,知道可以定义xml元素的类并且在用户类型XStream中没有映射这样的字段将决定“可能这个元素来自某个隐式集合”。如果你班上既没有这样的收藏也没有田地,它很快就会失败。在我的情况下,有问题的xml片段是这样的:

<url>http://somewhere.com</url>

当然,我班上既没有Url url;也没有@XStreamImplicit List<Url> url。拥有这样一个XML并使用“realClass”的结果如下:

com.thoughtworks.xstream.converters.ConversionException: Element url of type java.net.URL is not defined as field in type org.sample.xstream.SomeBean

正确的方式

如果false(不使用shouldSerializeMember内容),正确的方法是从definedIn == Object.class返回普通realClass(fieldName)

但仅仅使用return false是不够的。我这种形式会导致XStream将隐式集合留空。

这里的技巧是确保使用@XStreamImplicit(itemFieldName = "something")而不是仅使用@XStreamImplicit而不使用参数,即使在标记名称和集合的通用参数类型具有相同名称的情况下也是如此。

所以正确的代码如下所示:

    xstream = new XStream() {
        @Override
        protected MapperWrapper wrapMapper(MapperWrapper next) {
            return new MapperWrapper(next) {
                @Override
                public boolean shouldSerializeMember(Class definedIn, String fieldName) {
                    if (definedIn == Object.class) {
                        //This is not compatible with implicit collections where item name is not defined
                        return false;
                    } else {
                        return super.shouldSerializeMember(definedIn, fieldName);
                    }
                }
            };
        }
    };
    xsteam.processAnnotations(SomeRootEntry.class);

您需要确保在您的类中隐式集合的标记如下:

@XStreamImplicit(itemFieldName = "something")
private List <Something> somethingList;

请注意,即使List的泛型类型参数具有相同的名称,也会显式指定itemFieldName。这很重要。

在这种情况下遇到<something>标记时,XStream甚至不会使用该fieldName访问您的shouldSerializeMember。它将事先知道该元素来自隐式集合。

访问时,您的方法会再次遇到<url>http://somewhere.com</url>。但在这里我们是安全的,因为我们只返回false

适合我!试一试。

答案 4 :(得分:1)

在XStream实例中使用 ignoreUnknownElements()方法:

XStream xstream = new XStream();
xstream.ignoreUnknownElements();