代码之家  ›  专栏  ›  技术社区  ›  Artyom Sokolov

Java/JAXB:UNJARSURL XML属性到特定Java对象属性

  •  19
  • Artyom Sokolov  · 技术社区  · 14 年前

    有一个丑陋的XML文件必须解组:

    <?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>
    

    生成的Java对象应该是:

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

    This 问题的答案很接近,但我想不出最终的解决办法。

    2 回复  |  直到 7 年前
        1
  •  17
  •   bdoughan    14 年前

    怎么样?

    引入一个名为Options的通用超级类:

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

    然后在具有选项列表的类上(本例中的配置),在该属性上指定一个@xmljavatypeadapter:

    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将如下所示:

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

    自适应选项如下:

    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;
        }
    
    }
    
        2
  •  8
  •   axtavt    14 年前

    您可以创建一个单独的类来表示XML的结构:

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

    然后使用一个 XmlAdapter 要执行转换:

    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 { ... }