使用 JSXB 将 xml 通用映射到 java bean

问题描述 投票:0回答:1

我已将 xml 内容映射到 java bean。我正在使用 JAXB 将其转换为我的 bean 类。 这很好用。但为此我需要事先知道xml的内容。如果在 xml 中添加一些新元素,我必须更改代码。 我想避免这种情况。我怎样才能实现这个目标。

   <Mangos>
       <Mango name='mangoA' color='yellow' />
       <Mango name='mangoB' color='green' />
   </Mangos>
  <Bananas>
       <Banana name='bananaA' color='yellow' />
       <Banana name='bananaB' color='green' />
   </Bananas >
</Fruit >

@XmlRootElement(name = "Fruit")
@XmlAccessorType(XmlAccessType.FIELD)
public class Fruit {
   @XmlElementWrapper(name= "Mangos")
   @XmlElement(name = "Mango")
   private List<FruitPojo> mangos;

   @XmlElementWrapper(name= "Bananas")
   @XmlElement(name = "Banana")
   private List< FruitPojo > bananas;
}

public class FruitPojo {
   
   private String name;
   private String color;
}

java xml spring-boot jaxb
1个回答
0
投票

是的,当出现非建模水果(例如

Mangos
)时,可以为
Bananas
Apples
的 XSD 模型解组/编组 XML 文件,而无需更改代码。这是实现这一目标的方法...

关键概念

    <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>

示例 XML 文件

以下是两个示例 XML 文件。第一个文件仅包含由 XSD 文件建模的水果(请参阅下面的 XSD)。第二个样本包含建模和未建模的水果(

Apples
Cherries

fruit1.xml(已知水果)

<?xml version="1.0" encoding="UTF-8"?>
<Fruit
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="../../main/resources/fruit.xsd"
>
    <Mangos>
        <Mango name='mangoA' color='yellow' />
        <Mango name='mangoB' color='green' />
    </Mangos>
    <Bananas>
        <Banana name='bananaA' color='yellow' />
        <Banana name='bananaB' color='green' />
    </Bananas>
</Fruit>

fruit2.xml(已知和未知水果)

<?xml version="1.0" encoding="UTF-8"?>
<Fruit
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="../../main/resources/fruit.xsd"
>
    <Mangos>
        <Mango name='mangoA' color='yellow' />
        <Mango name='mangoB' color='green' />
    </Mangos>
    <Bananas>
        <Banana name='bananaA' color='yellow' />
        <Banana name='bananaB' color='green' />
    </Bananas>
    <Apples>
        <Apple name='appleA' color='yellow' />
        <Apple name='appleB' color='green' />
    </Apples>
    <Cherries>
        <Apple name='cherryA' color='black' />
        <Apple name='cherryB' color='red' />
    </Cherries>
</Fruit >

XML 架构 (XSD) 和绑定 (XJB) 文件

用于设置一些常见全局属性的 JAXB 绑定文件。

水果.xjb

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings jaxb:version="3.0"
    xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
>
    <jaxb:globalBindings localScoping="toplevel">
        <jaxb:serializable uid="20240501" />
    </jaxb:globalBindings>
</jaxb:bindings>

由 XML 架构文件描述的 Fruit 模型。

水果.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
    <!--
        Note: Top element(s) with anonymous complex type
              become XmlRootElement(s).
    -->
    <xs:element name="Fruit" >
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Mangos">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="Mango" minOccurs="0" maxOccurs="unbounded">
                                <xs:complexType>
                                    <xs:attribute name="name" type="xs:string"/>
                                    <xs:attribute name="color" type="xs:string"/>
                                </xs:complexType>
                            </xs:element>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                <xs:element name="Bananas">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="Banana" minOccurs="0" maxOccurs="unbounded">
                                <xs:complexType>
                                    <xs:attribute name="name" type="xs:string"/>
                                    <xs:attribute name="color" type="xs:string"/>
                                </xs:complexType>
                            </xs:element>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

JAXB/XJC生成的Fruit类

Fruit
类定义了三个XML元素:
Mangos
Bananas
Any
。第三个元素包含任意数量的未建模、非模式元素。

Fruit.java
(JAXB 生成)

package org.example.fruit;

import java.io.Serializable;
import java.util.*;
import jakarta.xml.bind.annotation.*;
import org.w3c.dom.Element;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = { "mangos", "bananas", "any" })
@XmlRootElement(name = "Fruit")
public class Fruit
    implements Serializable
{
    private static final long serialVersionUID = 20240501L;

    @XmlElement(name = "Mangos", required = true)
    protected Mangos mangos;
    public Mangos getMangos() { return mangos; }
    public void setMangos(Mangos value) { this.mangos = value; }

    @XmlElement(name = "Bananas", required = true)
    protected Bananas bananas;
    public Bananas getBananas() { return bananas; }
    public void setBananas(Bananas value) { this.bananas = value; }

    @XmlAnyElement(lax = true)
    protected List<Object> any;
    public List<Object> getAny() {
        if (any == null)
            any = new ArrayList<>();
        return this.any;
    }
}

输出(未编组和编组)

以下内容已在测试类中进行整理和整理。

fruit1.xml

[INFO] Running org.example.fruit.FruitTest
11:33:00:147 INFO Fruit:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Fruit>
    <Mangos>
        <Mango name="mangoA" color="yellow"/>
        <Mango name="mangoB" color="green"/>
    </Mangos>
    <Bananas>
        <Banana name="bananaA" color="yellow"/>
        <Banana name="bananaB" color="green"/>
    </Bananas>
</Fruit>

下一个输出显示包含未知水果的示例 XML 的往返结果。

fruit2.xml

11:33:00:180 INFO Fruit:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Fruit>
    <Mangos>
        <Mango name="mangoA" color="yellow"/>
        <Mango name="mangoB" color="green"/>
    </Mangos>
    <Bananas>
        <Banana name="bananaA" color="yellow"/>
        <Banana name="bananaB" color="green"/>
    </Bananas>
    <Apples xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <Apple color="yellow" name="appleA"/>
        <Apple color="green" name="appleB"/>
    </Apples>
    <Cherries xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <Apple color="black" name="cherryA"/>
        <Apple color="red" name="cherryB"/>
    </Cherries>
</Fruit>

单元测试源码和Maven POM

这是用于解组和编组两个 XML 文件的单元测试类。

FruitTest.java

package org.example.fruit;

import static jakarta.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT;
import static org.junit.jupiter.api.Assertions.fail;

import java.io.File;
import java.io.StringWriter;

import org.jvnet.basicjaxb.testing.AbstractSamplesTest;

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.Unmarshaller;

/**
 * A JUnit test to check a sample XML file.
 */
public class FruitTest extends AbstractSamplesTest
{
    @Override
    protected void checkSample(File sample)
        throws Exception
    {
        JAXBContext jaxbContext = createContext();

        Object root = getUnmarshaller().unmarshal(sample);
        
        if ( root instanceof Fruit )
        {
            Fruit fruit = (Fruit) root;

            String fruitXml = null;
            try ( StringWriter sw = new StringWriter() )
            {
                getMarshaller().marshal(fruit, sw);
                fruitXml = sw.toString();
            }
            getLogger().info("Fruit:\n\n" + fruitXml);
        }
        else
            fail("Object is not instance of Fruit: " + root);
    }
}

Maven POM 使用 HiSrc HighJAXB Maven 插件 来生成 JAXB 类。

免责声明:我是 HiSrc 项目的维护者。

Maven POM

<?xml version="1.0" encoding="UTF-8"?>
<project
    xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
>
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.patrodyne.jvnet</groupId>
    <artifactId>hisrc-higherjaxb-sample-fruit</artifactId>
    <version>2.2.1</version>
    <packaging>jar</packaging>
    <name>HiSrc HigherJAXB Assembly Sample [fruit]</name>

    <properties>
        <maven.compiler.release>11</maven.compiler.release>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <hisrc-basicjaxb.version>2.2.1</hisrc-basicjaxb.version>
        <hisrc-higherjaxb-maven-plugin.version>2.2.1</hisrc-higherjaxb-maven-plugin.version>
        <jaxb-api.version>4.0.2</jaxb-api.version>
        <jaxb-imp.version>4.0.5</jaxb-imp.version>
        <slf4j.version>2.0.12</slf4j.version>
    </properties>

    <dependencies>
        <!-- JAXB Runtime -->
        <dependency>
            <groupId>jakarta.xml.bind</groupId>
            <artifactId>jakarta.xml.bind-api</artifactId>
            <version>${jaxb-api.version}</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>${jaxb-imp.version}</version>
        </dependency>
        <!-- HiSrc BasicJAXB -->
        <dependency>
            <groupId>org.patrodyne.jvnet</groupId>
            <artifactId>hisrc-basicjaxb-testing</artifactId>
            <version>${hisrc-basicjaxb.version}</version>
        </dependency>
    </dependencies>

    <build>
        <defaultGoal>package</defaultGoal>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <compilerArgs>
                        <arg>-proc:full</arg>
                    </compilerArgs>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.1.2</version>
                <configuration>
                    <argLine>${env.JVM_SYS_ARGS}</argLine>
                    <systemPropertiesFile>${basedir}/src/test/resources/jvmsystem.properties</systemPropertiesFile>
                </configuration>
            </plugin>
            <!-- mvn hisrc-higherjaxb:help -Ddetail=true -->
            <!-- mvn hisrc-higherjaxb:generate -->
            <plugin>
                <groupId>org.patrodyne.jvnet</groupId>
                <artifactId>hisrc-higherjaxb-maven-plugin</artifactId>
                <version>${hisrc-higherjaxb-maven-plugin.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <generatePackage>org.example.fruit</generatePackage>
                    <noFileHeader>true</noFileHeader>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <!-- All modules for testing, etc. -->
        <profile>
            <id>all</id>
            <modules>
            </modules>
        </profile>

        <!-- Execution mode -->
        <profile>
            <id>exec</id>
            <dependencies>
                <dependency>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-simple</artifactId>
                    <version>${slf4j.version}</version>
                    <scope>runtime</scope>
                </dependency>
            </dependencies>
            <build>
                <resources>
                    <resource>
                        <directory>${basedir}/src/main/resources</directory>
                    </resource>
                    <resource>
                        <directory>${basedir}/src/test/resources</directory>
                    </resource>
                </resources>
            </build>
        </profile>

        <!-- Test mode -->
        <profile>
            <id>test</id>
            <dependencies>
                <dependency>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-simple</artifactId>
                    <version>${slf4j.version}</version>
                    <scope>test</scope>
                </dependency>
            </dependencies>
        </profile>
    </profiles>
</project>
<!-- vi:set tabstop=4 hardtabs=4 shiftwidth=4 noexpandtab:-->
© www.soinside.com 2019 - 2024. All rights reserved.