如何使用MOXy将XML元素属性解析为键值对?
Hey there! Let's figure out why your MOXy setup isn't populating that meta map correctly—this is a common gotcha, so we'll work through it step by step.
First, let's recap the goal: we want to parse <meta property="key" content="value"/> elements into a Map<String, String> where the property attribute is the key, and content is the value. Here are the most likely issues and fixes:
1. Verify Your Annotation Configuration
The @XmlVariableNode approach relies on precise annotation placement to link the XML attributes to your map. Let's make sure you're using it correctly:
Correct Entry Class Setup
If you're using the variable node approach, your Entry class should map the <meta> elements directly to the map, with annotations pointing to the property attribute as the key, and content as the value:
import org.eclipse.persistence.oxm.annotations.XmlVariableNode; import org.eclipse.persistence.oxm.annotations.XmlPath; import javax.xml.bind.annotation.XmlElement; public class Entry { // Map key comes from the "property" attribute of <meta> @XmlElement(name = "meta") @XmlVariableNode("@property") // Tell MOXy to pull the value from the "content" attribute @XmlPath("@content") private Map<String, String> metaMap; // Getters and setters public Map<String, String> getMetaMap() { return metaMap; } public void setMetaMap(Map<String, String> metaMap) { this.metaMap = metaMap; } }
Note: The @XmlPath("@content") is critical here—it tells MOXy which attribute to use for the map's value. Without this, MOXy won't know where to pull the value from.
2. Check Your MapAdapter Implementation
If you're using an XmlAdapter instead of @XmlVariableNode, make sure it's properly converting between the <meta> elements and the map. A common mistake is not handling the array of Meta objects correctly:
Correct MapAdapter Code
import javax.xml.bind.annotation.adapters.XmlAdapter; import java.util.HashMap; import java.util.Map; public class MapAdapter extends XmlAdapter<Meta[], Map<String, String>> { @Override public Map<String, String> unmarshal(Meta[] metaElements) throws Exception { Map<String, String> metaMap = new HashMap<>(); if (metaElements != null) { for (Meta meta : metaElements) { // Ensure property and content aren't null before adding if (meta.getProperty() != null && meta.getContent() != null) { metaMap.put(meta.getProperty(), meta.getContent()); } } } return metaMap; } @Override public Meta[] marshal(Map<String, String> metaMap) throws Exception { if (metaMap == null) { return new Meta[0]; } Meta[] metas = new Meta[metaMap.size()]; int index = 0; for (Map.Entry<String, String> entry : metaMap.entrySet()) { Meta meta = new Meta(); meta.setProperty(entry.getKey()); meta.setContent(entry.getValue()); metas[index++] = meta; } return metas; } }
Then link this adapter to your map in the Entry class:
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; public class Entry { @XmlElement(name = "meta") @XmlJavaTypeAdapter(MapAdapter.class) private Map<String, String> metaMap; // Getters and setters }
3. Ensure MOXy is Properly Enabled
MOXy isn't the default JAXB provider, so you need to explicitly configure it:
- Create a
jaxb.propertiesfile in the same package as your model classes (e.g., alongsideDMLData.java). - Add this line to the file:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Without this, your code will use the default JAXB implementation (from the JDK), which doesn't support MOXy-specific annotations like @XmlVariableNode.
4. Validate Your XML Structure
Double-check that your XML matches the structure your model expects. For example, if your Entry class is a child of DMLData, your XML should look like this:
<dmlData> <entry> <meta property="title" content="Sample Title"/> <meta property="author" content="John Doe"/> </entry> </dmlData>
If the <meta> elements are nested at a different level, your annotations won't pick them up.
Final Check: Test Your JAXB Context Creation
Make sure you're creating the JAXB context with all your model classes:
import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import java.io.File; public class ParserTest { public static void main(String[] args) throws Exception { JAXBContext jaxbContext = JAXBContext.newInstance(DMLData.class, Entry.class, Meta.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); DMLData data = (DMLData) unmarshaller.unmarshal(new File("input.xml")); // Check if the map is populated System.out.println(data.getEntry().getMetaMap()); } }
If you've gone through all these steps and still have issues, feel free to share your exact XML structure and full class code—I can help dig deeper!
内容的提问来源于stack exchange,提问作者GGKamal

