我已将 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;
}
是的,当出现非建模水果(例如
Mangos
)时,可以为 Bananas
和 Apples
的 XSD 模型解组/编组 XML 文件,而无需更改代码。这是实现这一目标的方法...
<xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
以下是两个示例 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 >
用于设置一些常见全局属性的 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>
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>
这是用于解组和编组两个 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:-->