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

问题描述:

我有一个很大的XML文档,我想转换为一个Java bean。它有很多标签和属性,但我只对其中的一小部分感兴趣。不言而喻,XStream似乎强迫你在该bean中为每个可能在该XML中的标记声明一个属性。有没有解决的办法?如何在解析XML时使XStream跳过未映射的标记?

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

对集合使用@XStreamImplicit注解时,这不起作用。有任何想法吗? – 2011-12-20 21:11:42

+0

使用@ com.thoughtworks.xstream.annotations.XStreamOmitField – timomeinen 2013-01-18 11:15:25

+0

XStreamOmitField不适用于我!没有XStream文档中提到的瞬态。 – endless 2013-05-03 21:42:57

我一直在工作我的方式解决这个问题,今天我所发现的是,使用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 

正确的方式

正确的方式将从shouldSerializeMember万一当definedIn == Object.class(不使用被返回平原falserealClass(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; 

注意itemFieldName是明确即使List的泛型类型参数具有相同的名称也是如此。这是至关重要的。

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

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

适合我!试一试。

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


由于

XStream的1.4.5 durring编组声明它足以使用ignoreEnknownElements()方法:

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

忽略不必要的元素。