XML中的Schema

本文详细介绍了XML Schema的作用和使用方法,包括定义XML文档结构、元素和属性、数据类型等。通过示例展示了如何创建XML Schema文件以及如何在XML文件中引用,还解释了schema中常见标签的功能。此外,还提及了如何快速生成XSD文件和为XSD添加注释,以及XML到Java数据结构的转换方法。
摘要由CSDN通过智能技术生成

XML中的Schema

对于``Schma`这个词我们可能了解得很少,但其实我们经常会用到,比如在Spring的配置文件中,在SpringMVC的配置文件中,一般我们创建一个Spring的配置文件都会在文件头写一段配置,比如Spring的配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>

然后我们再在其中写我们的bean配置,但此时我们会注意到一个问题,<beans></beans>标签里面只能写<bean></bean>,<alias></alias>等事先规定好的标签,如果写其他的标签的话就会报错,这是为什么呢?

image-20220624150601289

其实这就是Schema的作用。

1. Schema是什么?

XML Schema 的作用是定义 XML 文档的合法构建模块。XML Schema以XML语言为基础,也可以说XML Schema自身就是XML的一种应用。

XML Schema可定义的内容包括:

  • 定义可出现在文档中的元素
  • 定义可出现在文档中的属性
  • 定义哪个元素是子元素
  • 定义子元素的次序
  • 定义子元素的数目
  • 定义元素是否为空,或者是否可包含文本
  • 定义元素和属性的数据类型
  • 定义元素和属性的默认值以及固定值

2. 如何使用?

2.1 创建一个简单的XML文件

user.xml

<?xml version="1.0"?>
<user>
    <name>jack</name>
    <age>1</age>
    <bir>2022-01-01</bir>
    <desc>jack is a boy!</desc>
</user>

2.2 创建一个XSD文件

user.xsd,xsd后缀是Schema文件的后缀名称,该文件将定义user.xml文件的格式。

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://xuhao.com"
           xmlns="http://xuhao.com"
           elementFormDefault="qualified">

    <xs:element name="note">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="name" type="xs:string"/>
                <xs:element name="age" type="xs:string"/>
                <xs:element name="bir" type="xs:string"/>
                <xs:element name="desc" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

</xs:schema>

2.3 将XML关联XSD文件

<?xml version="1.0" encoding="UTF-8"?>
<user xmlns="http://xuhao.com"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://xuhao.com http://xuhao.com/user.xsd">
    <name>jack</name>
    <age>1</age>
    <bir>2022-01-01</bir>
    <desc>jack is a boy!</desc>
</user>

在user.xml文件中,我们关联了user.xsd文件,而我们在user.xsd文件中限制了可使用的标签,如果此时我们在user.xml文件中使用其他标签,此时文件就会报错。

3. Sechma中的标签解释

3.1 XSD文件中schema标签的解释

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://xuhao.com"
           xmlns="http://xuhao.com"
           elementFormDefault="qualified">

</xs:schema>

<schema> 元素是每一个XML Schema的根元素,它可包含以下属性。

# xmlns:xs="http://www.w3.org/2001/XMLSchema"
    显示 schema 中用到的元素和数据类型来自命名空间 "http://www.w3.org/2001/XMLSchema"。同时它还规定了来自命名空间 "http://www.w3.org/2001/XMLSchema" 的元素和数据类型应该使用前缀 xs:
    
# targetNamespace
	显示在这个xsd文件中定义的标签来自哪一个命名空间,上述我们配置的是http://xuhao.com,一般命名规则为:http://公司域名/xsd文件名
	
# xmlns
	默认的命名规则,一般和targetNamespace相同。
	
# elementFormDefault
	任何 XML 实例文档所使用的且在此 schema 中声明过的元素必须被命名空间限定。

3.2 XML文件中引用schema标签的解释

<?xml version="1.0" encoding="UTF-8"?>
<user xmlns="http://xuhao.com"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://xuhao.com http://xuhao.com/user.xsd">
    <name>jack</name>
    <age>1</age>
    <bir>2022-01-01</bir>
    <desc>jack is a boy!</desc>
</user>
# xmlns
	规定了默认命名空间的声明。此声明会告知 schema 验证器,在此 XML 文档中使用的所有元素都被声明于 "http://xuhao.com" 这个命名空间,和xsd配置的xmln相对应。
	
# xmlns:xsi
	xsi是http://www.w3.org/2001/XMLSchema-instance的别名。表示遵守w3的xml schema规范,xml解析器解析xml文件时,就明白按照什么规范解析了。xml schema规范有很多中,不止w3一家标准。
	
# xsi:schemaLocation
	由一个URI引用对组成,两个URI之间以空白符分隔。第一个URI是名称空间的名字,第二个URI给出xsd文件的位置,模式处理器将从这个位置读取模式文档,该模式文档的目标名称空间必须与第一个URI相匹配。上面的schemaLocation意为:在http://xuhao.com命名空间下的user.xsd文件。

3.3 schema中常见标签解释

3.3.1 annotation

可以包含 appinfo 元素(由应用程序使用的信息)和 documentation 元素(由用户读取或使用的注释或文本)。

3.3.2 restriction

定义一个约束条件。

3.3.3 sequence

规定标签中子元素的顺序。

3.3.4 attribute

规定标签的属性。

3.3.5 simpleType

定义一个简单类型, 用来规定和约束具有纯文本内容的元素(不含子元素即为具有纯文本内容的元素)或属性的值。

使用场景

1. 规定一个元素纯文本部分的类型,或规定一个元素属性的所属类型。 注意是纯文本
2. 当我们对一个元素纯文本的值,元素属性的值需要一些限制的时候。可参考:https://www.w3school.com.cn/schema/schema_elements_ref.asp

用法

规定一个元素纯文本内容的类型:

<xsd:element name="description" type="xsd:string"/>

规定一个元素属性的所属类型:

<xsd:element name="worker">
	<xsd:complexType>
		<xsd:attribute name="id" type="idType"/>
	</xsd:complexType>
</xsd:element>
 
<xsd:simpleType name="idType">
	<xsd:restriction base="xsd:integer"/>
</xsd:simpleType>

我定义了一个worker元素,并规定它具有一个id属性,这个属性的类型为idType,这是我自定义的一个simpleType,这个simpleType中规定了属性值的类型。
当然也可以直接将attributetype属性设置为xsd:integer,但我这样写是为了让大家更直观的看出simpleType确实可以规定一个元素属性的数据类型。

若父标签是element,则用来约束父标签所定义元素的纯文本内容:

<xsd:element name="gender">
	<xsd:simpleType>
		<xsd:restriction base="xsd:string">
			<xsd:enumeration value="Male"/>
			<xsd:enumeration value="Female"/>
		</xsd:restriction>
	</xsd:simpleType>
</xsd:element>

这个simpleType规定了它的父标签所定义的gender元素的纯文本内容是string类型,并且只能取MaleFemale两个值,起到了约束的作用。

若父标签是attribute,则用来约束父标签所定义的属性值:

<xsd:element name="person">
	<xsd:complexType>
		<xsd:attribute name="gender">
			<xsd:simpleType>
				<xsd:restriction base="xsd:string">
					<xsd:enumeration value="Male"/>
					<xsd:enumeration value="Female"/>
				</xsd:restriction>
			</xsd:simpleType>
		</xsd:attribute>
	</xsd:complexType>
</xsd:element>

这个simpleType规定了它的父标签所定义的person元素的gender属性值是string类型的,且只能取MaleFemale两个值。可以想象到spring配置文件中的是否设置为单例的开关的选项就是这样做的。

3.3.6 complexType

定义复杂类型,复杂类型的元素是包含其他元素和/或属性的 XML 元素。

用法

<student address="长沙">
	<name>zhagnsan</name>
    <age>14</age>
    <bir>2000-01-01</bir>
    <desc>未成年</desc>
</student>
<xs:element name="student">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="age" type="xs:string"/>
            <xs:element name="bir" type="xs:string"/>
            <xs:element name="desc" type="xs:string"/>
        </xs:sequence>
        <xsd:attribute name="addresss" type="xs:string"/>
    </xs:complexType>
</xs:element>

这个complexType为student元素定义了一个复杂类型,这个类型中包含了四个子元素:id,name,gender,addr,并且使用了sequence指示器指定了这四个子元素的顺序,还包含了一个class属性。

simpleType和complexType的区别

simpleType用来定义简单数据类型,其中可以包含对该类型内容的限制,可以指定某属性或元素属于某simpleType,从而起到规定元素文本内容和属性的作用。
complexType定义复杂数据类型,包含复杂的结构,如属性、序列关系(sequence)、选择关系(choice)等等,一般用于定义元素内容,可以指定某元素属于某complexType。

4. 快速生成XSD文件

我们可以使用trang工具来根据xml文件自动生成xsd文件,工具如下。

使用方法:

java -jar trang工具名称 xml文件位置 生成的xsd文件名称

示例

user.xml

<?xml version="1.0" encoding="UTF-8"?>
<data xmlns="http://fingard.com/quikeDev" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://fingard.com/quikeDev http://fingard.com/quikeDev/user.xsd">

    <user address="湖南长沙">
        <name>jack</name>
        <age>1</age>
        <bir>2022-01-01</bir>
        <desc>jack is a boy!</desc>
    </user>

    <teacher name="李四" isBoy="true">
        <age>12</sex>
    </teacher>
</data>

执行工具(trang-2009111.jar和user.xml都在同一个目录下,生成的user.xsd也在同一个目录)

java -jar .\trang-20091111.jar user.xml user.xsd

查看生成的user.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
           targetNamespace="http://fingard.com/quikeDev" xmlns:quikedev="http://fingard.com/quikeDev"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <xs:import namespace="http://www.w3.org/2001/XMLSchema-instance"/>
    <xs:element name="data">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="quikedev:user"/>
                <xs:element ref="quikedev:teacher"/>
            </xs:sequence>
            <xs:attribute ref="xsi:schemaLocation" use="required"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="user">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="quikedev:name"/>
                <xs:element ref="quikedev:age"/>
                <xs:element ref="quikedev:bir"/>
                <xs:element ref="quikedev:desc"/>
            </xs:sequence>
            <xs:attribute name="address" use="required" type="xs:NCName"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="name" type="xs:NCName"/>
    <xs:element name="bir" type="xs:NMTOKEN"/>
    <xs:element name="desc" type="xs:string"/>
    <xs:element name="teacher">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="quikedev:age"/>
            </xs:sequence>
            <xs:attribute name="isBoy" use="required" type="xs:boolean"/>
            <xs:attribute name="name" use="required" type="xs:NCName"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="age" type="xs:integer"/>
</xs:schema>

可以看到生成的xsd文件基本满足我们的要求,但各别标签的type不是我们想要的,我们可以自行进行更改。

5. 为XSD文件添加注释

有些时候我们在进行xml文件编写时,一些标签会提示该标签是做什么的,如下图:

image-20220624170604684

但我们自己编写的user.xml却没有提示,那么这个功能是怎么做到的呢?

image-202206241707115375.1 为标签添加注释

我们可以在xsd的命名空间配置中添加支持注释的命名空间,并在具体的标签中添加注释元素。用例如下:

xmlns:xhtml="http://www.w3.org/1999/xhtml"

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
           xmlns:xhtml="http://www.w3.org/1999/xhtml"
           targetNamespace="http://fingard.com/quikeDev" xmlns:quikedev="http://fingard.com/quikeDev"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <xs:element name="name" type="xs:string">
        <xs:annotation>
            <xs:documentation>
                <xhtml:p>姓名</xhtml:p>
            </xs:documentation>
        </xs:annotation>
    </xs:element>

</xs:schema>

此时当我们在IDEA中将光标放在标签上时就会出现提示。

image-20220624171254926

6. 解析XML,将XML转换为Java中的数据结构

代码中用到了dom4j,需要导入依赖。

<dependency>
    <groupId>org.dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>2.1.3</version>
</dependency>
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

/**
 * @author 许浩
 * @date 2022/6/24
 */
public class XmlTransUtil {

    public static List<HashMap<String, List<HashMap<String, String>>>> trans(String xml) {
        try {
            Document document = DocumentHelper.parseText(xml);
            Element rootElement = document.getRootElement();
            Iterator<Element> iterator = rootElement.elementIterator();
            List<HashMap<String, List<HashMap<String, String>>>> resultList = new ArrayList<>();
            // 外层crud
            while (iterator.hasNext()) {
                Element element = iterator.next();
                // 内部标签 pageCode,schema,tablePage,colConfig
                List<Element> elementList = element.elements();
                HashMap<String, List<HashMap<String, String>>> resultMap = new HashMap<>();
                for (Element e : elementList) {
                    List<HashMap<String, String>> result = new ArrayList<>();
                    constructedObject(e, result, -1);
                    resultMap.put(e.getName(), result);
                }
                resultList.add(resultMap);
            }
            return resultList;
        } catch (DocumentException e) {
            throw new RuntimeException("XML解析异常");
        }
    }

    private static void constructedObject(Element e, List<HashMap<String, String>> result, int level) {
        List<Element> elementList = e.elements();
        if (elementList.size() == 0) {
            HashMap<String, String> fieldMap = new HashMap<>();
            e.attributes().forEach(attr -> fieldMap.put(attr.getName(), attr.getValue()));
            String textTrim = e.getTextTrim();
            fieldMap.put(e.getName(), textTrim);
            result.add(fieldMap);
        }
        Iterator<Element> iterator = e.elementIterator();
        while (iterator.hasNext()) {
            Element element = iterator.next();
            if (level == -1) {
                HashMap<String, String> fieldMap = new HashMap<>();
                String text = element.getTextTrim();
                if (!StringUtils.isEmpty(text)) {
                    fieldMap.put(element.getName(), text);
                }
                element.attributes().forEach(attr -> fieldMap.put(attr.getName(), attr.getValue()));
                result.add(fieldMap);
                if (element.getParent() != null) {
                    HashMap<String, String> map = result.get(result.size() - 1);
                    Element parent1 = element.getParent();
                    parent1.attributes().forEach(attr -> map.put(attr.getName(), attr.getValue()));
                }
            } else {
                HashMap<String, String> map = result.get(result.size() - 1);
                String text = element.getText();
                if (!StringUtils.isEmpty(text)) {
                    map.put(element.getName(), text);
                }
                element.attributes().forEach(attr -> map.put(attr.getName(), attr.getValue()));
            }
            if (element.elements().size() > 0) {
                constructedObject(element, result, level + 1);
            }
        }
    }

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值