2010-07-19 14 views
19

unmarshalled zorundadır çirkin XML dosyası vardır:Java/JAXB: unmarshall XML belirli bir Java nesnesine niteliklerini nitelikleri

<?xml version="1.0" ?> 
<configuration> 
    <section name="default_options"> 
     <value name="default_port">8081</value> 
     <value name="log_level">WARNING</value> 
    </section> 
    <section name="custom_options"> 
     <value name="memory">64M</value> 
     <value name="compatibility">yes</value> 
    </section> 
</configuration> 

Ortaya Java nesneleri olmalıdır:

public class DefaultOptions { 
    private int defaultPort; 
    private String logLevel; 
    // etc... 
} 

public class CustomOptions { 
    private String memory; 
    private String compatibility; 
    // etc... 
} 

This Sorunun cevabı çok olduğu yakın ama nihai çözümü anlayamıyorum.

+0

Ortaya çıkan java nesnelerini değiştiremez misiniz? IMHO Eğer xml yapısını izlediyseniz (veya istediğiniz yapıyı takip etmek için değiştirdiyseniz) çok daha kolay ve daha temiz olacaktır. –

+0

@Diego Dias, aslında hayır. Bunlar gibi POJO'lar olmalı. –

+0

StandartOptions ve CustomOptions'a ortak bir süper sınıf eklenebilir mi? –

cevap

16

ne dersiniz?

tanıtılması, ortak bir süper sınıf olarak adlandırılan seçenekler: seçenekleri (bu örnekte Configuration) listesi ile classınıza Sonra

import javax.xml.bind.annotation.XmlAttribute; 

public abstract class Options { 

    private String name; 

    @XmlAttribute 
    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

} 

, o mülk üzerinde bir @XmlJavaTypeAdapter belirtin:

import java.util.ArrayList; 
import java.util.List; 

import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 

@XmlRootElement 
public class Configuration { 

    private List<Options> section = new ArrayList<Options>(); 

    @XmlJavaTypeAdapter(OptionsAdapter.class) 
    public List<Options> getSection() { 
     return section; 
    } 

    public void setSection(List<Options> section) { 
     this.section = section; 
    } 

} 

XmlAdapter şöyle bir şeye benzeyecektir:

import javax.xml.bind.annotation.adapters.XmlAdapter; 

public class OptionsAdapter extends XmlAdapter<AdaptedOptions, Options> { 

    @Override 
    public Options unmarshal(AdaptedOptions v) throws Exception { 
     if("default_options".equals(v.name)) { 
      DefaultOptions options = new DefaultOptions(); 
      options.setName(v.getName()); 
      options.setDefaultPort(Integer.valueOf(v.map.get("default_port"))); 
      options.setLogLevel(v.map.get("log_level")); 
      return options; 
     } else { 
      CustomOptions options = new CustomOptions(); 
      options.setName(v.getName()); 
      options.setCompatibility(v.map.get("compatibility")); 
      options.setMemory(v.map.get("memory")); 
      return options; 
     } 
    } 

    @Override 
    public AdaptedOptions marshal(Options v) throws Exception { 
     AdaptedOptions adaptedOptions = new AdaptedOptions(); 
     adaptedOptions.setName(v.getName()); 
     if(DefaultOptions.class == v.getClass()) { 
      DefaultOptions options = (DefaultOptions) v; 
      adaptedOptions.map.put("default_port", String.valueOf(options.getDefaultPort())); 
      adaptedOptions.map.put("log_level", options.getLogLevel()); 
     } else { 
      CustomOptions options = (CustomOptions) v; 
      adaptedOptions.map.put("compatibility", options.getCompatibility()); 
      adaptedOptions.map.put("memory", options.getMemory()); 
     } 
     return adaptedOptions; 
    } 

} 

AdaptedOption s şunun gibi görünüyor:

import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
import java.util.Map.Entry; 

import javax.xml.bind.Marshaller; 
import javax.xml.bind.Unmarshaller; 
import javax.xml.bind.annotation.XmlAttribute; 
import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlValue; 

public class AdaptedOptions extends Options { 

    @XmlAttribute String name; 
    @XmlElement List<Value> value = new ArrayList<Value>(); 
    Map<String, String> map = new HashMap<String, String>(); 

    public void beforeMarshal(Marshaller marshaller) { 
     for(Entry<String, String> entry : map.entrySet()) { 
      Value aValue = new Value(); 
      aValue.name = entry.getKey(); 
      aValue.value = entry.getValue(); 
      value.add(aValue); 
     } 
    } 

    public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) { 
     for(Value aValue : value) { 
      map.put(aValue.name, aValue.value); 
     } 
    } 

    private static class Value { 
     @XmlAttribute String name; 
     @XmlValue String value; 
    } 

} 
8

Sen XML yapısını temsil etmek ayrı sınıflar oluşturabilir:

public class Section { 
    @XmlAttribute 
    public String name; 
    @XmlElement(name = "value") 
    public List<Value> values; 
} 

public class Value { 
    @XmlAttribute 
    public String name; 
    @XmlValue 
    public String value; 
} 

ve sonra bir XmlAdapter dönüşümü gerçekleştirmek için kullanın:

public class OptionsAdapter extends XmlAdapter<Section, Options> { 
    public Options unmarshal(Section s) { 
     if ("default_options".equals(s.name)) { 
      ... 
     } else if (...) { 
      ... 
     } 
     ... 
    } 
    ... 
} 

@XmlElement 
public class Configuration { 
    @XmlElement(name = "section") 
    @XmlJavaTypeAdapter(OptionsAdapter.class) 
    public List<Options> options; 
} 

public class DefaultOptions extends Options { ... } 
public class CustomOptions extends Options { ... } 
+0

İlginç bir çözüm. Öncelikle teşekkür ederim. Deneyeceğim. Sorunu çözmenin tek yolu bu mu? Ya da belki "if (" default_options ".equals (s.name)) olmadan biraz daha zarif çözümler var"? –

+0

@Artyom: JAXB, hedef sınıfını nitelik değerinden çıkaramadığından, bir şekilde manuel bir yönlendirme gerektirir. Elbette bunu daha soyut bir şekilde yapabilirsiniz, ör. nitelik değerlerinden bir seçenek fabrikasına seçenekler kullanın. – axtavt

İlgili konular