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

发布于 2024-10-24 23:24:00 字数 126 浏览 5 评论 0原文

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

I have a large XML document that I want to convert to a Java bean. It has a lot of tags and attributes, but I'm interested only in a handful of those. Unfurtounately, it seems that XStream forces you to declare a property in that bean for each and every tag that may ever be in that XML. Is there a way around this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

我们只是彼此的过ke 2024-10-31 23:24:00

如下所示初始化 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);
            }
        };
    }
};

Initialize XStream as shown below to ignore fields that are not defined in your 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);
            }
        };
    }
};
苍景流年 2024-10-31 23:24:00

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


XStream 1.4.5 makes you simple to deal with unknown tags. Use ignoreUnknownElements() for tags which are not implemented yet or has been removed and you are dealing with old xml. You can also specify which particular tag you would like to ignore.


你在看孤独的风景 2024-10-31 23:24:00

自 XStream 1.4.5 起,在编组器声明期间使用ignoreEnknownElements() 方法就足够了:

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

忽略不必要的元素。

Since XStream 1.4.5 durring marshaller declaration it's enough to use ignoreEnknownElements() method:

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

to ignore unnecessary elements.

記憶穿過時間隧道 2024-10-31 23:24:00

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

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

事实上,使用的技巧是

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

有效的。它的作用是尝试通过标签名称猜测类型,看看是否成功,如果不成功,则返回 false。因此,它会完美地跳过像

<someUnknownTag>someContent</someUnknownTag>

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

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

当然,既没有 Url url; 也没有 @XStreamImplicit List; 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

正确的方法

正确的方法是从 shouldSerializeMemberfalse > 如果 defineIn == 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 也是显式指定的。这一点至关重要。

在这种情况下,遇到 标签时,XStream 甚至不会使用该 fieldName 访问您的 shouldSerializeMember。它只是提前知道该元素来自隐式集合。

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

对我有用!尝试一下。

I've been working my way around this problem today and what I've found out is that using return this.realClass(fieldName) != null; is not (always) a working solution however actually there is a way for XStream to skip unmapped tags AND work with implicit collections at the same time.

Why realClass(fieldName) thing won't work

In fact trick with using

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

works. What it does is attempt to guess the type by the tag name, see whether it succeeded and if not - returns false. So it'll perfectly skip tags like

<someUnknownTag>someContent</someUnknownTag>

BUT it will work only up to the moment (!) when somehow some "not needed" tag will happen to have a meaningful name for which realClass(fieldName) will be actually able to return something not equal to null and that tag won't be a member of any ImplicitCollection of yours. In that case knowing that the class for an xml element could be defined and there is no such field mapped in users type XStream will decide that "maybe this element is from some implicit collection". And it will fail very soon if there is neither such collection nor a field in your class. In my case the problematic piece of xml was like this:

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

and, of course, there was neither Url url; nor @XStreamImplicit List<Url> url on my class. The result of having such an XML and using "realClass" thing is as follows:

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

The right way

The right way would be returning plain false from shouldSerializeMember in case when definedIn == Object.class (not using realClass(fieldName) stuff).

But just using return false alone is not enough. I this form it will cause XStream to leave implicit collections empty.

The trick here is to make sure that one uses @XStreamImplicit(itemFieldName = "something") instead of just using @XStreamImplicit without parameters even in the cases when tag name and collection's generic param type have the same name.

So the right code will look like this:

    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);

And you need to be sure that in your classes your implicit collections are marked like this:

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

Notice that itemFieldName is explicitly specified even though List's generic type parameter has the same name. This is crucial.

In this case upon encountering <something> tag XStream won't even visit your shouldSerializeMember with that fieldName. It will just know in advance that the element is from implicit collections.

When it will visit your method is upon encountering <url>http://somewhere.com</url> again. But here we're safe since we just return false.

Works for me! Give it a try.

染年凉城似染瑾 2024-10-31 23:24:00

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

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

Use ignoreUnknownElements() method in your XStream instance:

XStream xstream = new XStream();
xstream.ignoreUnknownElements();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文