You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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&lt;java.lang.String, java.lang.String&gt;"/>
            </jaxb:property>
            <!-- 指定用我们自定义的适配器处理转换 -->
            <xjc:javaType adapter="com.yourpackage.MultiLangMapAdapter" name="java.util.Map&lt;java.lang.String, java.lang.String&gt;"/>
        </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&lt;java.lang.String, java.lang.String&gt;"/>
            </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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 13:22:59