Подтвердить что ты не робот

Как заставить XStream пропускать немаркированные теги при разборе XML?

У меня есть большой XML-документ, который я хочу преобразовать в Java bean. В нем много тегов и атрибутов, но меня интересует только несколько из них. Безгранично кажется, что XStream заставляет вас объявить свойство в bean для каждого тега, который может когда-либо быть в этом XML. Есть ли способ обойти это?

4b9b3361

Ответ 1

Инициализируйте 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);
            }
        };
    }
};

Ответ 2

XStream 1.4.5 упрощает работу с неизвестными тегами. Используйте ignoreUnknownElements для тегов, которые еще не реализованы или были удалены, и вы имеете дело со старым xml http://x-stream.github.io/javadoc/com/thoughtworks/xstream/XStream.html#ignoreUnknownElements%28%29. Вы также можете указать, какой конкретный тег вы хотите игнорировать.


Ответ 3

Так как XStream 1.4.5 выдает объявление маршаллера, достаточно использовать метод ignoreEnknownElements():

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

игнорировать ненужные элементы.

Ответ 4

Сегодня я столкнулся с этой проблемой, и выяснилось, что использование 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

Правильный путь

Правильный путь будет возвращать plain false из shouldSerializeMember в случае, если definedIn == Object.class (не используя realClass(fieldName) stuff).

Но просто использовать только 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;

Обратите внимание, что itemFieldName явно задан, даже если параметр типа Generic типа имеет то же имя. Это важно.

В этом случае при столкновении с тегом <something> XStream даже не будет посещать ваш shouldSerializeMember с этим полемName. Он просто будет знать заранее, что элемент из неявных коллекций.

Когда он посетит ваш метод, снова встретите <url>http://somewhere.com</url>. Но здесь мы в безопасности, так как мы просто возвращаем false.

Работает для меня! Попробуйте.