3

伙计们,

我不熟悉使用 JAXB 编组和解组对象的世界。

我正在尝试编组一个可以最好地说是地图列表的对象。

我试图达到的最终结果如下:

<parametricSearchResult>
   <allFilters>
      <name>custom_year</name>
      <name>abcd</name>
   </allFilters>
   <allFields>
      <field>
         <name>custom_year</name>
         <value count="10">2012</value>
         <value count="8">2011</value>
      </field>
      <field>
         <name>abcd</name>
         <value count="8">2011</value>
      </field>
   </allFields>
</parametricSearchResult>

使用我编写的代码,我将其作为输出

<parametricSearchResult>
    <allFilters>
        <name>custom_year</name>
        <name>abcd</name>
    </allFilters>
    <allFields>
        <allFilters>
            <mName>test</mName>
            <field>
                <value count="10">
                    <mValue>2012</mValue>
                </value>
                <value count="8">
                    <mValue>2011</mValue>
                </value>
            </field>
            <name>test</name>
        </allFilters>
        <allFilters>
            <mName>test</mName>
            <field>
                <value count="4">
                    <mValue>2011</mValue>
                </value>
            </field>
            <name>test</name>
        </allFilters>
    </allFields>
</parametricSearchResult>

我的代码如下

参数搜索结果

@XmlRootElement(name = "parametricSearchResult")
public class ParametricSearchResult {

    private final List<String> mFilterFields = new ArrayList<String>();

    private final List<Map<String, Integer>> mFiltersToCountsMap = new ArrayList<Map<String, Integer>>();

    public void setFilterFields(List<String> fields) {
        mFilterFields.addAll(fields);
    }

    @XmlElementWrapper(name = "allFilters")
    @XmlElement(name = "name")
    public List<String> getFilterFields() {
        return mFilterFields;
    }

    @XmlElement(name = "allFields")
    @XmlJavaTypeAdapter(JAXBParametricSearchResultSerializer.class)
    public List<Map<String, Integer>> getValuesAndCounts() {
        return mFiltersToCountsMap;
    }

    public void addFilterFieldsAndCounts(final String field, final String filterValue, final Integer count) {
        final int index = mFilterFields.indexOf(field.toLowerCase());
        if (index == -1) {
            mFilterFields.add(field.toLowerCase());
            HashMap<String, Integer> mapValuesToCounts = new HashMap<String, Integer>();
            mapValuesToCounts.put(filterValue.toLowerCase(), Integer.valueOf(count));
            mFiltersToCountsMap.add(mapValuesToCounts);
        } else {
            Map<String, Integer> mapValuesToCounts = mFiltersToCountsMap.get(index);
            mapValuesToCounts.put(filterValue.toLowerCase(), Integer.valueOf(count));
        }
    }

    public Map<String, Integer> getFilterValueToCountMap(String filterName) {
        final int index = mFilterFields.indexOf(filterName.toLowerCase());
        if (index == -1) {
            return new HashMap<String, Integer>();
        } else {
            return mFiltersToCountsMap.get(index);
        }
    }   
}

参数搜索结果类型

public class ParametricSearchResultType {

    private final List<ParametricFilterType> allFilters = new ArrayList<ParametricFilterType>();

    @XmlElement
    public List<ParametricFilterType> getFilters() {
        return allFilters;
    }

    public void setFilter(final ParametricFilterType data) {
        allFilters.add(data);
    }
}

参数过滤器类型

public class ParametricFilterType {

    private String mName = "";

    private final List<ParametricMapEntryType> mFilterAllEntries = new ArrayList<ParametricMapEntryType>();

    @XmlElement(name = "name")
    public String getName() {
        return mName;
    }

    public void setName(final String data) {
        mName = data;
    }

    public void setAllFilters(final ParametricMapEntryType data) {
        mFilterAllEntries.add(data);
    }

    @XmlElementWrapper(name = "field")
    @XmlElement(name = "value")
    public final List<ParametricMapEntryType> getAllFilterEntries() {
        return mFilterAllEntries;
    }
}

参数映射条目类型

public class ParametricMapEntryType {

    @XmlValue
    public String mValue;

    @XmlAttribute(name = "count")
    public Integer mCount;

}

JAXB参数搜索结果序列化器

public class JAXBParametricSearchResultSerializer extends XmlAdapter<ParametricSearchResultType, List<Map<String, Integer>>> {

    @Override
    public ParametricSearchResultType marshal(final List<Map<String, Integer>> data) throws Exception {
        ParametricSearchResultType result = new ParametricSearchResultType();
        for (Map<String, Integer> aMap : data) {
            ParametricFilterType filters = new ParametricFilterType();
            filters.mName = "test";
            for (Map.Entry<String, Integer> anEntry : aMap.entrySet()) {
                ParametricMapEntryType entry = new ParametricMapEntryType();
                entry.mValue = anEntry.getKey();
                entry.mCount = anEntry.getValue();
                filters.mFilterAllEntries.add(entry);
            }
            result.allFilters.add(filters);
        }
        return result;
    }

    @Override
    public List<Map<String, Integer>> unmarshal(final ParametricSearchResultType data) throws Exception {
        return null;
    }

}

参数搜索结果测试器

public class ParametricSearchResultTester {

    ParametricSearchResult mResult;

    @Before
    public void setUp() throws Throwable {

        mResult = new ParametricSearchResult();
        mResult.addFilterFieldsAndCounts("CUSTOM_YEAR", "2012", 10);
        mResult.addFilterFieldsAndCounts("CUSTOM_YEAR", "2011", 8);
        mResult.addFilterFieldsAndCounts("ABCD", "2011", 4);
    }

    @After
    public void tearDown() throws Throwable {
        mResult = null;
    }

    @Test
    public void testThatMarshallingWorks() throws Throwable {
        JAXBContext context = JAXBContext.newInstance(ParametricSearchResult.class);
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.marshal(mResult, System.out);
    }
}

在阅读更多文档后对代码进行了一些更改并进行了这些更改后,我最终将其作为输出

<parametricSearchResult>
    <allFilters>
        <name>custom_year</name>
        <name>abcd</name>
    </allFilters>
    <allFields>
        <filters>
            <field>
                <value count="10">2012</value>
                <value count="8">2011</value>
            </field>
            <name>test</name>
        </filters>
        <filters>
            <field>
                <value count="4">2011</value>
            </field>
            <name>test</name>
        </filters>
    </allFields>
</parametricSearchResult>

几乎就在那里,但仍然需要对元素进行更多的清理和重新排列。不知道还能在这里做什么。

4

3 回答 3

0

JAXB 不擅长处理 Map,因此需要一个适配器。基本上,大多数地图适配器将地图转换为条目列表。一旦你有了一个好的适配器,你就可以拥有一个扩展 List> 的对象,然后该对象可以包含到 List 本身中。

您可能能够让您的 XML 看起来与您希望的完全一样,但需要更多的摆弄,但是当用于实例化泛型的类型不同时,此解决方案将不可移植。

于 2012-08-08T23:05:03.450 回答
0

I'm sorry. I can't give you the very expected answer without any deep understanding of your requirements, business, and so on.

Here comes my pseudo try.

@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement
@XmlType(propOrder = {"filterNames", "fields"})
public class ParametricSearchResult {


    @XmlAccessorType(XmlAccessType.NONE)
    @XmlType(propOrder = {"name", "values"})
    public static class Field {


        public static Field newInstance(final String name,
                                        final Value... values) {

            final Field instance = new Field();

            instance.setName(name);

            for (Value value : values) {
                instance.getValues().add(value);
            }

            return instance;
        }


        @XmlAccessorType(XmlAccessType.NONE)
        public static class Value {


            public static Value newInstance(final int count,
                                            final String value) {

                final Value instance = new Value();

                instance.setCount(count);
                instance.setValue(value);

                return instance;
            }


            public int getCount() {
                return count;
            }


            public void setCount(final int count) {
                this.count = count;
            }


            public String getValue() {
                return value;
            }


            public void setValue(final String value) {
                this.value = value;
            }


            @XmlAttribute(required = true)
            private int count;


            @XmlValue
            private String value;


        }


        public String getName() {
            return name;
        }


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


        public Collection<Value> getValues() {

            if (values == null) {
                values = new ArrayList<Value>();
            }

            return values;
        }


        @XmlElement(required = true)
        private String name;


        @XmlElement(name = "value")
        private Collection<Value> values;


    }


    public static void main(final String[] args)
        throws JAXBException, IOException {

        final ParametricSearchResult result = new ParametricSearchResult();

        result.getFilterNames().add("custom_year");
        result.getFilterNames().add("abcd");

        result.getFields().add(
            Field.newInstance(
            "custom_year",
            Value.newInstance(10, "2012"),
            Value.newInstance(8, "2011")));

        result.getFields().add(
            Field.newInstance(
            "abcd",
            Value.newInstance(8, "2011")));

        final JAXBContext context =
            JAXBContext.newInstance(ParametricSearchResult.class);

        final Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

        marshaller.marshal(result, System.out);

        System.out.println("-------------------------------------------------");

        context.generateSchema(new SchemaOutputResolver() {


            @Override
            public Result createOutput(final String namespaceUri,
                                       final String suggestedFileName)
                throws IOException {

                return new StreamResult(System.out) {


                    @Override
                    public String getSystemId() {
                        return "noid";
                    }


                };
            }


        });
    }


    public Collection<String> getFilterNames() {

        if (filterNames == null) {
            filterNames = new ArrayList<String>();
        }

        return filterNames;
    }


    public Collection<Field> getFields() {

        if (fields == null) {
            fields = new ArrayList<Field>();
        }

        return fields;
    }


    @XmlElement(name = "name")
    @XmlElementWrapper(name = "allFilters", nillable = true, required = true)
    private Collection<String> filterNames;


    @XmlElement(name = "field")
    @XmlElementWrapper(name = "allFields", nillable = true, required = true)
    private Collection<Field> fields;


}

prints

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<parametricSearchResult>
    <allFilters>
        <name>custom_year</name>
        <name>abcd</name>
    </allFilters>
    <allFields>
        <field>
            <name>custom_year</name>
            <value count="10">2012</value>
            <value count="8">2011</value>
        </field>
        <field>
            <name>abcd</name>
            <value count="8">2011</value>
        </field>
    </allFields>
</parametricSearchResult>

and here comes the XML Schema.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="parametricSearchResult" type="parametricSearchResult"/>

  <xs:complexType name="parametricSearchResult">
    <xs:sequence>
      <xs:element name="allFilters" nillable="true">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="name" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="allFields" nillable="true">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="field" type="field" minOccurs="0" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="field">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="value" type="value" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="value">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="count" type="xs:int" use="required"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:schema>
于 2012-08-01T15:02:04.887 回答
0

伙计们,

在考虑了一段时间之后,我重新设计了尝试创建不同对象的方式。

这就是我为解决我的困惑所做的。我创建了三个新类,如下所示。在做了更多阅读之后,这就是我想出的。

参数SingleFilterMapEntry

public class ParametricSingleFilterMapEntry {

    private String mValue;

    private Integer mCount;

    public void setValue(final String data) {
        mValue = data;
    }

    @XmlValue
    public String getValue() {
        return mValue;
    }

    public void setCount(final Integer count) {
        mCount = count;
    }

    @XmlAttribute(name = "count")
    public Integer getCount() {
        return mCount;
    }
}

下一个包含 ParametricSingleFilterMapEntry 列表的类

参数单过滤器所有条目

@XmlType(propOrder = {"fieldName", "allEntriesForSingleField"})
public class ParametricSingleFilterAllEntries {

    private String mFilterField;

    private final List<ParametricSingleFilterMapEntry> mAllEntriesForSingleField = new ArrayList<ParametricSingleFilterMapEntry>();

    public void setField(final String name) {
        mFilterField = name;
    }

    @XmlElement(name = "name")
    public String getFieldName() {
       return mFilterField;
    }

    public void setAllMapEntries(final List<ParametricSingleFilterMapEntry> data) {
        mAllEntriesForSingleField.addAll(data);
    }

    public void setAMapEntry(final ParametricSingleFilterMapEntry entry) {
        mAllEntriesForSingleField.add(entry);
    }

    @XmlElement(name = "value")
    public List<ParametricSingleFilterMapEntry> getAllEntriesForSingleField() {
        return mAllEntriesForSingleField;
    }    
}

最后一类将上述两个类很好地联系在一起

参数搜索结果

@XmlRootElement(name = "parametricSearchResult")
public class ParametricSearchResult {

    private final List<ParametricSingleFilterAllEntries> mAllFilterEntries = new ArrayList<ParametricSingleFilterAllEntries>();

    @XmlElementWrapper(name = "allFields")
    @XmlElement(name = "field")
    public List<ParametricSingleFilterAllEntries> getAllFilterEntries() {
        return mAllFilterEntries;
    }

    public void addEntry(final ParametricSingleFilterAllEntries entry) {
        mAllFilterEntries.add(entry);
    }

    public void addEntries(final List<ParametricSingleFilterAllEntries> entries) {
        mAllFilterEntries.addAll(entries);
    }

    public void addEntry(final String filterName, final String filterValue, final Integer count) {
        if (StringUtils.isNotBlank(filterName)) {
            ParametricSingleFilterMapEntry newMapEntry = new ParametricSingleFilterMapEntry();
            newMapEntry.setValue(filterValue);
            newMapEntry.setCount(count);
            if (mAllFilterEntries.isEmpty()) {
                ParametricSingleFilterAllEntries newFilterEntry = new ParametricSingleFilterAllEntries();
                newFilterEntry.setField(filterName);
                newFilterEntry.setAMapEntry(newMapEntry);                
                addEntry(newFilterEntry);
                return;
            } else {
                ParametricSingleFilterAllEntries newFilterEntry = new ParametricSingleFilterAllEntries();
                for (ParametricSingleFilterAllEntries entry : mAllFilterEntries) {
                    if (StringUtils.isNotBlank(entry.getFieldName())) {
                        if (entry.getFieldName().equalsIgnoreCase(filterName)) {
                            entry.setAMapEntr(newMapEntry);                            
                            return;
                        } else {
                            continue;
                        }
                    }
                }
                newFilterEntry.setField(filterName);
                newFilterEntry.setAMapEntry(newMapEntry);                        
                addEntry(newFilterEntry);
            }
        }
    }
}

希望这种方法可以帮助其他可能面临类似问题的人。

于 2012-08-29T15:30:34.060 回答