如何使用JAXB在Java类中生成Map以处理带xml:lang属性的XSD元素
如何使用JAXB在Java类中生成Map以处理带xml:lang属性的XSD元素
嘿,我之前在项目里刚好处理过一模一样的需求——用JAXB生成Java类时,把带xml:lang属性的XSD元素转成Map<String, String>,再也不用面对一堆重复的类了!下面我就把实操步骤给你捋清楚:
先明确你的XSD结构(补全示例)
先给你补全这类元素的简化XSD结构,方便你对照理解:
<xsd:element name="textileMaterialThreadCount"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute ref="xml:lang" use="required"/> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> <!-- 假设还有个包含这类元素的父类型 --> <xsd:complexType name="Product"> <xsd:sequence> <xsd:element ref="textileMaterialThreadCount" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType>
第一步:编写JAXB绑定文件(binding.xjb)
这一步是核心,用来告诉JAXB怎么把XML结构映射成我们想要的Map。你可以创建一个binding.xjb文件,配置如下:
<jaxb:bindings version="2.1" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"> <!-- 关联你的XSD文件 --> <jaxb:bindings schemaLocation="your-schema.xsd" node="/xsd:schema"> <!-- 针对Product类型里的textileMaterialThreadCount元素集合配置映射 --> <jaxb:bindings node="xsd:complexType[@name='Product']/xsd:sequence/xsd:element[@ref='textileMaterialThreadCount']"> <!-- 指定生成的Java属性名为threadCountMap --> <jaxb:property> <jaxb:name>threadCountMap</jaxb:name> <jaxb:baseType name="java.util.Map<java.lang.String, java.lang.String>"/> </jaxb:property> <!-- 指定用我们自定义的适配器处理转换 --> <xjc:javaType adapter="com.yourpackage.MultiLangMapAdapter" name="java.util.Map<java.lang.String, java.lang.String>"/> </jaxb:bindings> <!-- 如果你有很多这类带xml:lang的元素,可以用通用匹配规则,不用一个个配置 --> <!-- <jaxb:bindings node="//xsd:complexType[xsd:simpleContent/xsd:extension/xsd:attribute[@ref='xml:lang']]"> <jaxb:property> <jaxb:baseType name="java.util.Map<java.lang.String, java.lang.String>"/> </jaxb:property> <xjc:javaType adapter="com.yourpackage.MultiLangMapAdapter"/> </jaxb:bindings> --> </jaxb:bindings> </jaxb:bindings>
第二步:实现自定义XmlAdapter
JAXB本身不会自动把XML元素的属性和文本转成Map,所以我们需要写一个XmlAdapter子类,负责序列化(Java→XML)和反序列化(XML→Java)时的转换逻辑:
package com.yourpackage; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlValue; import javax.xml.bind.annotation.adapters.XmlAdapter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class MultiLangMapAdapter extends XmlAdapter<MultiLangMapAdapter.AdaptedLangItems, Map<String, String>> { // 中间类:对应XML里的多个带lang属性的元素集合 public static class AdaptedLangItems { @XmlElement(name = "textileMaterialThreadCount") public List<AdaptedLangItem> items = new ArrayList<>(); } // 中间类:对应单个带lang属性的XML元素 public static class AdaptedLangItem { // 一定要指定xml:lang的命名空间,不然JAXB识别不到 @XmlAttribute(namespace = "http://www.w3.org/XML/1998/namespace") public String lang; // 对应元素的文本内容 @XmlValue public String value; } // 把XML结构转成Java Map @Override public Map<String, String> unmarshal(AdaptedLangItems v) throws Exception { Map<String, String> langMap = new HashMap<>(); if (v != null && v.items != null) { for (AdaptedLangItem item : v.items) { if (item.lang != null && item.value != null) { langMap.put(item.lang, item.value); } } } return langMap; } // 把Java Map转成XML结构 @Override public AdaptedLangItems marshal(Map<String, String> v) throws Exception { AdaptedLangItems adaptedItems = new AdaptedLangItems(); if (v != null && !v.isEmpty()) { for (Map.Entry<String, String> entry : v.entrySet()) { AdaptedLangItem item = new AdaptedLangItem(); item.lang = entry.getKey(); item.value = entry.getValue(); adaptedItems.items.add(item); } } return adaptedItems; } }
第三步:生成Java类
现在就可以用JAXB的xjc工具或者Maven插件生成代码了:
用命令行xjc工具
xjc -b binding.xjb your-schema.xsd -d src/main/java -p com.yourpackage
参数说明:
-b:指定绑定文件-d:指定生成代码的输出目录-p:指定生成类的包名
用Maven的jaxb2-maven-plugin
如果是Maven项目,直接在pom.xml里配置插件,执行mvn jaxb2:xjc就能生成代码:
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxb2-maven-plugin</artifactId> <version>2.5.0</version> <executions> <execution> <goals> <goal>xjc</goal> </goals> </execution> </executions> <configuration> <schemaDirectory>src/main/resources</schemaDirectory> <bindingDirectory>src/main/resources</bindingDirectory> <bindingFiles>binding.xjb</bindingFiles> <packageName>com.yourpackage</packageName> </configuration> </plugin>
一些要注意的细节
- 一定要正确指定
xml:lang的命名空间http://www.w3.org/XML/1998/namespace,不然JAXB无法识别这个属性。 - 如果你的XSD里只有单个带lang属性的元素(不是集合),可以简化适配器,只处理单个元素转Map的逻辑。
- 通用匹配规则虽然方便,但要注意不要误匹配到其他不需要转Map的元素,最好先测试再用。
内容来源于stack exchange
相关产品推荐
相关产品推荐

