JAXB:如何在使用Map时删除包装标签

时间:2016-06-17 10:40:53

标签: java xml jaxb

我在编组时使用variable vQuery = " where condition"; select * from table1 " + vQuery; select * from table2 " + vQuery; select * from table3 " + vQuery; @XmlJavaTypeAdapter个对象转换为Map<Key, Value>,而在取消编组时将其转换为List<Value>

然后我获得的XML:

<map>
    <value>VALUE1</value>
...
</map>

我的问题是:如何摆脱周围的标签以获取

<value>VALUE1</value>

Bean类

@XmlAccessorType(XmlAccessType.FIELD)
public class Data implements Serializable {

  /**
   * Constant for data value default name
   */
  public static final String DATA_VALUE_DEFAULT_NAME = "result";

  /**
   * Serial version UID
   */
  private static final long serialVersionUID = 7387937212735185585L;

  /**
   * key
   */
  @XmlAttribute
  private String key;

  /**
   * name
   */
  @XmlAttribute
  private String name;

  /**
   * Map of data
   */
  @XmlJavaTypeAdapter(MapDataAdapter.class)
  private Map<String, Data> dataMap;

  /**
   * Constructor
   */
  public Data() {

  }
}

适配器

public class MapDataAdapter 
  extends XmlAdapter<MapDataAdapter.AdaptedDataMap,
                     Map<String, Data>> {

  /**
   * Adapted map
   */
  public static class AdaptedDataMap {

    /**
     * List of entry
     */
    @XmlElement(name = "data", required = true)
    protected List<Data> entry = new ArrayList<>();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Map<String, Data> unmarshal(
    AdaptedDataMap adaptedMap) throws Exception {
    if (adaptedMap == null) {
     return null;
    }
    Map<String, Data> map = new HashMap<>(adaptedMap.entry.size());
    for (Data entry : adaptedMap.entry) {
      map.put(entry.getKey(), entry);
    }
    return map;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public AdaptedDataMap marshal(
      Map<String, Data> map) throws Exception {
    if (map == null) {
      return null;
    }
    AdaptedDataMap adaptedMap = new AdaptedDataMap();
    for (Entry<String, Data> mapEntry : map.entrySet()) {
      adaptedMap.entry.add(mapEntry.getValue());
    }
    return adaptedMap;
  }
}

XML输出

<data key="12" name="TEST1">
    <dataMap>
        <data key="text" name="TEST2">
            <dataMap>
                <data key="azerty" name="TEST3">
                </data>
            </dataMap>
        </data>
    </dataMap>
</data>

我需要什么

<data key="12" name="TEST1">
    <data key="text" name="TEST2">
            <data key="azerty" name="TEST3">
            </data>
    </data>
</data>

2 个答案:

答案 0 :(得分:0)

JAXB映射/继承/不带元素包装器

要在没有元素包装器的情况下将元素从地图中编组/拆组,可以实现一个List,该列表将数据存储在Map中。 JAXB会将其视为简单列表,并且知道如何处理。

我开发此方法是因为@XmlJavaTypeAdapter似乎与@XmlElements@XmlElementRefs不兼容。实际上,javadocs说@XmlJavaTypeAdapter可以与@XmlElementRefs结合使用,但是它对我没有用。我一直在抓ClassCastException。

替代方法立即解决了两个问题:

  • 不需要元素包装器
  • 允许使用@XmlElements映射

ExampleDocument.java

@XmlRootElement(name="example-document")
@XmlAccessorType(XmlAccessType.NONE)
public class ExampleDocument
{
  @XmlElements
  (
    {
      @XmlElement( name="child1" type=Child1.class ),
      @XmlElement( name="child2", type=Child2.class )
    }
  )
  private ChildrenList children = new ChildrenList();

  public Children getChildById( String id ) 
  { 
    return children.getMap().get( id ); 
  }
  public Collection<Children> allChildren()
  {
    return children.getMap().values();
  }
}

Children.java

@XmlTransient
public class Children
{
  private String id;
}

Child1.java

@XmlType
public class Child1 extends Children
{
}

Child2.java

@XmlType
public class Child2 extends Children
{
}

ChildrenList.java

public class ChildList implements List<Children>
{
  private Map<String,Children> map 
     = new TreeMap<String,Children>();

  @Override
  public boolean add( Children c ) 
  {
    return map.put( c.getId(), c ) != null;
  }
  @Override
  public boolean remove( Object o )
  {
    return map.remove( ((Children)o).getId() ) != null;
  }
  @Override
  public int size()
  {
    return map.size();
  }
  @Override
  public boolean isEmpty()
  {
    return map.isEmpty();
  }
  @Override
  public boolean contains( Object o )
  {
    return map.containsKey( ((Children)o).getId() );
  }
  @Override
  public Iterator<Children> iterator()
  {
    return map.values().iterator();
  }
  @Override
  public Object[] toArray()
  {
    return map.values().toArray();
  }
  @Override
  public <T> T[] toArray( T[] ts )
  {
    return map.values().toArray( ts );
  }
  @Override
  public boolean addAll( Collection<? extends ArticleBiblio> collection )
  {
    boolean result = false;
    for( ArticleBiblio b : collection )
    {
      result |= add( b );
    }
    return result;
  }

  /* all other methods throws UnsupportedOperationException */
}

答案 1 :(得分:0)

我喜欢Lucas的解决方案,并通过使其通用以防止不必要的类型检查在此进行扩展。

列表项抽象类

abstract class MapListItem<K> {
    /* Note that we can't implement this here, because we may want to rename or restructure the key attribute in the XML */
    public abstract K getKey();
}

示例商品类别

public class ItemA extends MapListItem<String>{
    @XmlAttribute(name="keyA")
    public String key;
    @XmlElement(name = "valueA")
    public ArrayList<ValueA> values = new ArrayList<>();

    public ItemA(String key) {
        this.key = key;
    }

    public ItemA(String key, ArrayList<ValueA> values) {
        this(key);
        this.values = values;
    }

    @Override
    public String getKey() {
        return key;
    }

}

通用地图列表-K是键类型,V是值类型,还包含一个键。

public class MapList<K, V extends MapListItem<K>> implements List<V> {
    private Map<K, V> map = new TreeMap<>();

    public MapList(Collection<? extends V> collection) {
        addAll(collection);
    }

    @Override
    public boolean add(V c) {
        return map.put(c.getKey(), c) != null;
    }

    @Override
    public boolean remove(Object o) {
        return map.remove(((V) o).getKey()) != null;
    }

    @Override
    public int size() {
        return map.size();
    }

    @Override
    public boolean isEmpty() {
        return map.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        return map.containsKey(((V) o).getKey());
    }

    @Override
    public Iterator<V> iterator() {
        return map.values().iterator();
    }

    @Override
    public Object[] toArray() {
        return map.values().toArray();
    }

    @Override
    public <T> T[] toArray(T[] ts) {
        return map.values().toArray(ts);
    }

    @Override
    public boolean addAll(Collection<? extends V> collection) {
        boolean result = false;
        for (V b : collection) {
            result |= add(b);
        }
        return result;
    }
}

现在,我们可以像这样创建一个MapList:

@XmlElement(name = "itemA")
public MapList<String,ItemA> itemAs;