<?xml version='1.0' encoding='UTF-8'?>
<!-- edited with XMLSpy v2011 sp1 (http://www.altova.com) by Roger Hughes (Marin Solutions Ltd) -->
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:ppp='http://www.petesperfectpizza.com' xmlns:cust='http://customer.dets' targetNamespace='http://www.petesperfectpizza.com' elementFormDefault='qualified' attributeFormDefault='unqualified' version='1.00'>
<!-- Import the Namespaces required -->
<xs:import namespace='http://customer.dets' schemaLocation='customer.xsd'/>
<!-- The Root Node -->
<xs:element name='PizzaOrder'>
<xs:annotation>
<xs:documentation>A wrapper around the customer and the pizza order</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name='orderID' type='ppp:CorrelationIdentifierType'/>
<xs:element name='date' type='ppp:DateType'/>
<xs:element name='time' type='ppp:TimeType'/>
<xs:element name='Customer' type='cust:CustomerType'/>
<xs:element ref='ppp:pizzas'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- The Pizza Order-->
<xs:element name='pizzas'>
<xs:annotation>
<xs:documentation>This is a list of pizzas ordered by the customer</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name='pizza' type='ppp:PizzaType' minOccurs='1' maxOccurs='unbounded'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name='PizzaType'>
<xs:sequence>
<xs:element name='name' type='ppp:PizzaNameType'>
<xs:annotation>
<xs:documentation>The type of pizza on the menu</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name='base' type='ppp:BaseType'>
<xs:annotation>
<xs:documentation>type of base</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name='quantity' type='ppp:QuantityType'>
<xs:annotation>
<xs:documentation>quantity of pizzas</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:simpleType name='PizzaNameType'>
<xs:restriction base='xs:token'>
<xs:enumeration value='Margherita'>
<xs:annotation>
<xs:documentation>Plain and Simple</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value='Marinara'>
<xs:annotation>
<xs:documentation>Garlic Pizza...</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value='Prosciutto e Funghi'>
<xs:annotation>
<xs:documentation>Ham and Musheroom</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value='Capricciosa'>
<xs:annotation>
<xs:documentation>with an egg</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name='BaseType'>
<xs:restriction base='xs:token'>
<xs:enumeration value='thin'>
<xs:annotation>
<xs:documentation>thin base traditional</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value='thick'>
<xs:annotation>
<xs:documentation>Thick base</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name='QuantityType'>
<xs:restriction base='xs:nonNegativeInteger'/>
</xs:simpleType>
<xs:simpleType name='CorrelationIdentifierType'>
<xs:restriction base='xs:token'>
<xs:maxLength value='44'/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name='DateType'>
<xs:annotation>
<xs:documentation>The date is in the Common Era (minus sign in years is not permitted)</xs:documentation>
</xs:annotation>
<xs:restriction base='xs:date'>
<xs:pattern value='\d{4}-\d{2}-\d{2}'/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name='TimeType'>
<xs:annotation>
<xs:documentation>The time zone although not included UTC is implied</xs:documentation>
</xs:annotation>
<xs:restriction base='xs:time'>
<xs:pattern value='\d{2}:\d{2}:\d{2}(\.\d+)?'/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
<?xml version='1.0' encoding='UTF-8'?>
<!-- edited with XMLSpy v2011 sp1 (http://www.altova.com) by Roger Hughes (Marin Solutions Ltd) -->
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:cust='http://customer.dets' targetNamespace='http://customer.dets' elementFormDefault='qualified' attributeFormDefault='unqualified'>
<xs:element name='Customer' type='cust:CustomerType'>
<xs:annotation>
<xs:documentation>Generic Customer Definition</xs:documentation>
</xs:annotation>
</xs:element>
<xs:complexType name='CustomerType'>
<xs:sequence>
<xs:element name='name' type='cust:NameType'/>
<xs:element name='phone' type='cust:PhoneNumberType'/>
<xs:element name='address' type='cust:AddressType'/>
</xs:sequence>
</xs:complexType>
<xs:complexType name='NameType'>
<xs:sequence>
<xs:element name='firstName' type='cust:FirstNameType'/>
<xs:element name='lastName' type='cust:LastNameType'/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name='FirstNameType'>
<xs:annotation>
<xs:documentation>The Customer's first name</xs:documentation>
</xs:annotation>
<xs:restriction base='xs:token'>
<xs:maxLength value='16'/>
<xs:pattern value='.{1,16}'/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name='LastNameType'>
<xs:annotation>
<xs:documentation>The Customer's surname</xs:documentation>
</xs:annotation>
<xs:restriction base='xs:token'>
<xs:pattern value='.{1,48}'/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name='AddressType'>
<xs:sequence>
<xs:element name='houseNumber' type='cust:HouseNumberType'/>
<xs:element name='street' type='cust:AddressLineType'/>
<xs:element name='town' type='cust:AddressLineType' minOccurs='0'/>
<xs:element name='area' type='cust:AddressLineType' minOccurs='0'/>
<xs:element name='postCode' type='cust:PostCodeType'/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name='HouseNumberType'>
<xs:annotation>
<xs:documentation>The house number</xs:documentation>
</xs:annotation>
<xs:restriction base='xs:nonNegativeInteger'/>
</xs:simpleType>
<xs:simpleType name='AddressLineType'>
<xs:annotation>
<xs:documentation>A line of an address</xs:documentation>
</xs:annotation>
<xs:restriction base='xs:token'>
<xs:pattern value='.{1,100}'/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name='PhoneNumberType'>
<xs:restriction base='xs:token'>
<xs:maxLength value='18'/>
<xs:pattern value='.{1,18}'/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name='PostCodeType'>
<xs:restriction base='xs:token'>
<xs:maxLength value='10'/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
您意识到以这种级别的复杂性,您将在很长一段时间内迷失于SAX,并且还可能犯一些错误。 必须有更好的方法吧? 毕竟XML已经存在了一段时间,因此必须有一些有用的框架。 经过更多的Google搜索之后,您发现JAXB并意识到……
JAXB或用于XML绑定的Java体系结构使用JAXB绑定编译器xjc将XML模式隐藏到一堆相关的Java类中。 这些定义了以类型安全的方式访问XML元素,属性和其他内容所需的类型。 本博客不是涵盖JAXB内容的教程,可以在Oracle,Oracle , Glassfish,Project Metro和JAXB页面上找到 ,它也包括一个教程 。 除了说解析或解组XML的关键思想外,您还可以使用xjc编译器编译Java类,然后将这些类与JAXB API结合使用来获取XML元素和属性。
在将任何XML模式用于Java类编译器时,最巧妙的方法是将所有模式及其编译的类放入单独的JAR文件中。 您可以将它们与应用程序的源代码混合在一起,但是通常会使代码库模糊,从而使维护更加困难。 在创建JAXB JAR文件时,您可能会想到一个类似于以下内容的POM文件:
<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>com.captaindebug</groupId>
<artifactId>xml-tips-jaxb</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>Jaxb for Pete's Perfect Pizza</name>
<dependencies>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.sun.tools.xjc.maven2</groupId>
<artifactId>maven-jaxb-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<generatePackage>com.captaindebug.jaxb</generatePackage>
<includeSchemas>
<includeSchema>**/*.xsd</includeSchema>
</includeSchemas>
<strict>true</strict>
<verbose>true</verbose>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
……这很简单。 因此,回到Pete的Perfect Pizza ,您已经创建了JAXB JAR文件,剩下要做的就是探索其工作方式,如下面的JUnit测试所示:
@Test
public void testLoadPizzaOrderXml() throws JAXBException, IOException {
InputStream is = loadResource('/pizza-order1.xml');
// Load the file
JAXBContext context = JAXBContext.newInstance(PizzaOrder.class);
Unmarshaller um = context.createUnmarshaller();
PizzaOrder pizzaOrder = (PizzaOrder) um.unmarshal(is);
String orderId = pizzaOrder.getOrderID();
assertEquals('123w3454r5', orderId);
// Check the customer details...
CustomerType customerType = pizzaOrder.getCustomer();
NameType nameType = customerType.getName();
String firstName = nameType.getFirstName();
assertEquals('John', firstName);
String lastName = nameType.getLastName();
assertEquals('Miggins', lastName);
AddressType address = customerType.getAddress();
assertEquals(new BigInteger('15'), address.getHouseNumber());
assertEquals('Credability Street', address.getStreet());
assertEquals('Any Town', address.getTown());
assertEquals('Any Where', address.getArea());
assertEquals('AW12 3WS', address.getPostCode());
Pizzas pizzas = pizzaOrder.getPizzas();
List<PizzaType> pizzasOrdered = pizzas.getPizza();
assertEquals(3, pizzasOrdered.size());
// Check the pizza order...
for (PizzaType pizza : pizzasOrdered) {
PizzaNameType pizzaName = pizza.getName();
if ((PizzaNameType.CAPRICCIOSA == pizzaName) || (PizzaNameType.MARINARA == pizzaName)) {
assertEquals(BaseType.THICK, pizza.getBase());
assertEquals(new BigInteger('1'), pizza.getQuantity());
} else if (PizzaNameType.PROSCIUTTO_E_FUNGHI == pizzaName) {
assertEquals(BaseType.THIN, pizza.getBase());
assertEquals(new BigInteger('2'), pizza.getQuantity());
} else {
fail('Whoops, can't find pizza type');
}
}
}
private InputStream loadResource(String filename) throws IOException {
InputStream is = getClass().getResourceAsStream(filename);
if (is == null) {
throw new IOException('Can't find the file: ' + filename);
}
return is;
}
上面的代码可能看起来很长而且很复杂,但实际上仅包括三个步骤:
- 将测试文件转换为输入流。 然后可以由JAXB API处理。
- 创建一个JAXB上下文及其关联的解组器。 然后将其用于读取XML并将其转换为元素和属性对象(如果有)
- 使用返回的类列表来测试内容是否符合我们的期望(到目前为止,这是最大的一步)。
一旦对JAXB的大量用法感到满意,就可以将其添加到厨房XML解析器代码中,并将其分布到Pete的许多披萨厨房中。
使用JAXB之类的框架的优点之一是,如果对架构进行了更改,那么合并这些更改所需要做的就是使用XJC重新编译,然后相应地修复客户端代码。 这似乎有点让人头疼,但是与尝试重新制作SAX解析器相比,它要头痛得多。 不利的一面是,JAXB因运行缓慢而受到批评,但我从来没有遇到太多问题。 从理论上讲,它将使用比SAX更多的内存–这可能是正确的,也可能不是。 它确实构建了类集,但同样会重复一些SAX ContentHandler派生的类。
应当记住,JAXB并不是采用这种方法的唯一工具,为了演示这一点,我的下一个博客也讲述了同样的故事,但是使用XMLBeans。
可从GitHub上获得源代码:
git://github.com/roghughe/captaindebug.git
继续阅读本系列的第4部分 。
参考: Captain Debug的Blog博客中的JCG合作伙伴 Roger Hughes的XML方法–第3部分– JAXB 。
翻译自: https://www.javacodegeeks.com/2012/07/approaches-to-xml-part-3-jaxb.html