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

Fix*_*int 20 xml xstream

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

Som*_*omu 20

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);
            }
        };
    }
};
Run Code Online (Sandbox Code Playgroud)

  • 在集合上使用@XStreamImplicit注释时,这对我不起作用.有任何想法吗? (2认同)

Aji*_*mar 18

XStream 1.4.5使您可以轻松处理未知标记.使用ignoreUnknownElements()了这些尚未实施或已被删除,你正在处理的旧XML标记.您还可以指定要忽略的特定标记.



krz*_*ste 9

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

XStreamMarshaller marshaller = new XStreamMarshaller();
marshaller.getXStream().ignoreUnknownElements();
...
Run Code Online (Sandbox Code Playgroud)

忽略不必要的元素.


Pla*_*ton 7

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

为什么realClass(fieldName)事情不起作用

事实上,使用技巧

try {
    return this.realClass(fieldName) != null;
} catch (Throwable t) {
    return false;
}
Run Code Online (Sandbox Code Playgroud)

作品.它的作用是尝试通过标记名称猜测类型,看它是否成功,如果不成功 - 返回false.所以它完全可以跳过像这样的标签

<someUnknownTag>someContent</someUnknownTag>
Run Code Online (Sandbox Code Playgroud)

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

<url>http://somewhere.com</url>
Run Code Online (Sandbox Code Playgroud)

当然,我的课上也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
Run Code Online (Sandbox Code Playgroud)

正确的方式

正确的方式是false从(不使用东西)的shouldSerializeMember情况下返回.definedIn == Object.classrealClass(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);
Run Code Online (Sandbox Code Playgroud)

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

@XStreamImplicit(itemFieldName = "something")
private List <Something> somethingList;
Run Code Online (Sandbox Code Playgroud)

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

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

什么时候它访问你的方法是在遇到<url>http://somewhere.com</url>再次.但是在这里我们安全,因为我们回来了false.

适合我!试试看.