民间,
我是使用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>
我的代码如下:
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);
}
}
}
ParametricSearchResultType
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);
}
}
ParametricFilterType
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;
}
}
ParametricMapEntryType
public class ParametricMapEntryType {
@XmlValue
public String mValue;
@XmlAttribute(name = "count")
public Integer mCount;
}
JAXBParametricSearchResultSerializer
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;
}
}
ParametricSearchResultTester
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>
几乎在那里,但仍需要更多的清理和重新排列元素。不知道还有什么可以做的。
答案 0 :(得分:0)
对不起如果不深入了解您的要求,业务等,我无法给出您期望的答案。
这是我的伪尝试。
@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;
}
打印
<?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>
这里是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>
答案 1 :(得分:0)
JAXB不擅长处理Map,因此需要适配器。基本上,大多数地图适配器将地图转换为条目列表。一旦你有一个好的适配器,你可以有一个扩展List&gt;的对象,然后该对象可以包含在List本身中。
您可能能够让您的XML看起来与您想要的更加简洁,但是当用于实例化泛型的类型不同时,此解决方案将不可移植。
答案 2 :(得分:0)
民间,
经过一段时间的研究,我改变了我试图创造不同物体的方式。
这就是我为解决问题而采取的措施。我创建了三个新类,如下所示。在做了一些阅读之后,这就是我想出来的。
<强> ParametricSingleFilterMapEntry 强>
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
列表的下一个类<强> ParametricSingleFilterAllEntries 强>
@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;
}
}
最后一节很好地将上述两个类联系起来
<强> ParametricSearchResult 强>
@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);
}
}
}
}
希望这种方法可以帮助其他可能遇到类似问题的人。