XML Schema学习笔记

本文详细介绍了XML Schema的定义、使用方法及其各种高级特性,包括简单的类型、复杂的类型、数据类型等,并提供了丰富的示例帮助理解。

一、简介

  XML Schema 语言也称作 XML Schema 定义(XML Schema Definition,XSD)。XML Schema 的作用是定义 XML 文档的合法构建模块,类似 DTD。

XML Schema:

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

XML Schema 使用 XML 语法,因此有很多好处:

  • 不必学习新的语言,了解XML即可
  • 可使用 XML 编辑器来编辑 Schema 文件
  • 可使用 XML 解析器来解析 Schema 文件
  • 可通过 XML DOM 来处理 Schema
  • 可通过 XSLT 来转换 Schema

如果对XML的命名空间不理解的可参考:XML学习笔记

XML Schema 参考手册

1.1 XSD - <schema> 元素

  <schema> 元素是每一个 XML Schema 的根元素:

<?xml version="1.0"?>
<xs:schema>
...
</xs:schema>

  <schema> 元素可包含属性。一个 schema 声明往往看上去类似这样:

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

上面代码解释:

xmlns:xs="http://www.w3.org/2001/XMLSchema"

  显示 schema 中用到的元素和数据类型来自命名空间 "http://www.w3.org/2001/XMLSchema"。同时它还规定了来自命名空间 "http://www.w3.org/2001/XMLSchema" 的元素和数据类型应该使用前缀 xs:

targetNamespace="http://www.w3school.com.cn"

  显示被此 schema 定义的元素来自命名空间: "http://www.w3school.com.cn"。

xmlns="http://www.w3school.com.cn" 

  指出默认的命名空间是 "http://www.w3school.com.cn"。

elementFormDefault="qualified" 

  指出任何 XML 实例文档所使用的且在此 schema 中声明过的元素必须被命名空间限定。

1.2 在 XML 文档中引用 Schema

<?xml version="1.0"?>
<note xmlns="http://www.w3school.com.cn"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.w3school.com.cn note.xsd">
...
</note>

  其中note只是这个XML文件的根元素。
上面代码解释:

xmlns="http://www.w3school.com.cn"

  规定了默认命名空间的声明。此声明会告知 schema 验证器,在此 XML 文档中使用的所有元素都被声明于 "http://www.w3school.com.cn" 这个命名空间。
  一旦您拥有了可用的 XML Schema 实例命名空间:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

  您就可以使用 schemaLocation 属性了。此属性有两个值。第一个值是需要使用的命名空间。第二个值是供命名空间使用的 XML schema 的位置:

xsi:schemaLocation="http://www.w3school.com.cn note.xsd"

  XML和Schema的命名空间标签使用格式是相同的(这也是Schema相对与DTD的优势),但XML和Schema都有各自的独特的属性,这也是由他们不同的功能决定的,Schema主要给XML提供服务,所以会规定好targetNameSpace来声明命名空间的名字,而XML需要使用schema的服务,所以需要SchemaLocation来声明使用的命名空间。

二、Schema深入之简单的类型

XML Schema 拥有很多内建的数据类型:

  • xs:string
  • xs:decimal
  • xs:integer
  • xs:boolean
  • xs:date
  • xs:time

2.1 XSD 简易元素

  XML Schema 可定义 XML 文件的元素。简易元素指那些只包含文本的元素,它不会包含任何其他的元素或属性。
定义简易元素的语法:

<xs:element name="xxx" type="yyy"/>

  此处 xxx 指元素的名称,yyy 指元素的数据类型。

  简易元素也可以设置默认值和固定值,通过default属性指定默认值,使用fixed属性指定固定值,示例如下:

简易元素定义:

<xs:element name="lastname" type="xs:string"/>
<xs:element name="age" type="xs:integer"/>
<xs:element name="dateborn" type="xs:date"/> 

对应的XML 元素使用示例:

<lastname>Smith</lastname>
<age>28</age>
<dateborn>1980-03-27</dateborn>

2.2 XSD 属性

  简易元素无法拥有属性。假如某个元素拥有属性,它就会被当作某种复合类型。但是属性本身总是作为简易类型被声明的。

定义属性的语法是:

<xs:attribute name="xxx" type="yyy"/>

  在此处,xxx 指属性名称,yyy 则规定属性的数据类型。

  同样属性也可以设置默认值和固定值,通过default属性指定默认值,使用fixed属性指定固定值

  在缺省的情况下,属性是可选的。如需规定属性为必选,我们需要使用 "use" 属性

<xs:attribute name="lang" type="xs:string" use="required"/>

2.3 XSD 限定 / Facets

  当 XML 元素或属性拥有被定义的数据类型时,就会向元素或属性的内容添加限定。假如 XML 元素的类型是 "xs:date",而其包含的内容是类似 "Hello World" 的字符串,元素将不会(通过)验证。这是对简易元素/属性的基本限定。

  限定(restriction)用于为 XML 元素或者属性定义可接受的值。对 XML 元素的限定被称为 facet。
  如果使用限定,那么气type(类型)属性就不能使用内建的数据类型,这个时候我们就需要使用自定义类型了,其形式如下:

<xs:element name="...">
	<xs:simpleType>
	  ...
	</xs:simpleType>
</xs:element> 

但是有时候也会遇到下面的形式:

<xs:element name="..." type="typeName">
	<xs:simpleType name="typeName">
	  ...
	</xs:simpleType>
</xs:element>

  有什么区别吗?第一种形式中xs:element中没有指定type类型,因为它默认使用的就是其内部定义的类型。然而xs:simpleType并不是当前定义元素的组成部分,换句话说,其可以被其它xs:element所使用。这样只需要在xs:element标签的属性type中指定这个xs:simpleType的name值即可,这也就是第二种形式。
  然后使用restriction 元素定义对simpleType等元素进行定义约束,restriction元素包含一个必选属性base,该属性规定在该 schema(或由指定的命名空间指示的其他 schema)中定义的内建数据类型、simpleType 或 complexType 元素的名称。形式如下:

<xs:element name="...">
	<xs:simpleType>
	  <xs:restriction base="...">
	  	...
	  </xs:restriction>
	</xs:simpleType>
</xs:element>  

restriction语法如下:

<restriction id=ID base=QName any attributes >

Content for simpleType:
(annotation),(simpleType),(minExclusive|minInclusive| 
maxExclusive|maxInclusive|totalDigits|fractionDigits|
length|minLength|maxLength|enumeration|whiteSpace|pattern)*))

Content for simpleContent:
(annotation),(simpleType),(minExclusive |minInclusive| 
maxExclusive|maxInclusive|totalDigits|fractionDigits|
length|minLength|maxLength|enumeration|whiteSpace|pattern)*)?, 
((attribute|attributeGroup)*,anyAttribute?))

Content for complexContent:
(annotation?,(group|all|choice|sequence)?,
((attribute|attributeGroup)*,anyAttribute?))

</restriction>

 

2.3.1 对值的限定(minInclusive&maxInclusive)

下面的例子定义了带有一个限定且名为 "age" 的元素。age 的值不能低于 0 或者高于 120:

<xs:element name="age">
	<xs:simpleType>
	  <xs:restriction base="xs:integer">
	    <xs:minInclusive value="0"/>
	    <xs:maxInclusive value="120"/>
	  </xs:restriction>
	</xs:simpleType>
</xs:element> 

2.3.2 对一组值的限定(enumeration)

如需把 XML 元素的内容限制为一组可接受的值,我们要使用枚举约束(enumeration constraint)。
下面的例子定义了带有一个限定的名为 "car" 的元素。可接受的值只有:Audi, Golf, BMW:

<xs:element name="car">
	<xs:simpleType>
	  <xs:restriction base="xs:string">
	    <xs:enumeration value="Audi"/>
	    <xs:enumeration value="Golf"/>
	    <xs:enumeration value="BMW"/>
	  </xs:restriction>
	</xs:simpleType>
</xs:element> 

2.3.3 对一系列值的限定(pattern)

如需把 XML 元素的内容限制定义为一系列可使用的数字或字母,我们要使用模式约束(pattern constraint)。
下面的例子定义了带有一个限定的名为 "letter" 的元素。可接受的值只有小写字母 a - z 其中的一个:

<xs:element name="letter">
	<xs:simpleType>
	  <xs:restriction base="xs:string">
	    <xs:pattern value="[a-z]"/>
	  </xs:restriction>
	</xs:simpleType>
</xs:element> 

注:如果您对正则表达式有所了解,name对value值就不会感到陌生。正则表达式可不止只是上面的这一个功能,更多详细正则表达式功能在此不详细叙述。关于pattern的一些示例可以参考:http://www.w3school.com.cn/schema/schema_facets.asp

2.3.4 对空白字符的限定(whiteSpace)

如需规定对空白字符(whitespace characters)的处理方式,我们需要使用 whiteSpace 限定。
下面的例子定义了带有一个限定的名为 "address" 的元素。whiteSpace 限定的值包含如下几个:

  • replace:意味着 XML 处理器将移除所有空白字符(换行、回车、空格以及制表符)
  • collapse:这意味着 XML 处理器将移除所有空白字符(换行、回车、空格以及制表符会被替换为空格,开头和结尾的空格会被移除,而多个连续的空格会被缩减为一个单一的空格)
  • preserve:意味着 XML 处理器不会移除任何空白字符:
<xs:element name="address">
	<xs:simpleType>
	  <xs:restriction base="xs:string">
	    <xs:whiteSpace value="preserve"/>
	  </xs:restriction>
	</xs:simpleType>
</xs:element> 

2.3.5 对长度的限定(length&minLength&maxLength)

如需限制元素中值的长度,我们需要使用 length、maxLength 以及 minLength 限定。
本例定义了带有一个限定且名为 "password" 的元素。其值必须精确到 8 个字符:

<xs:element name="password">
	<xs:simpleType>
	  <xs:restriction base="xs:string">
	    <xs:length value="8"/>
	  </xs:restriction>
	</xs:simpleType>
</xs:element> 

定义了带有一个限定的名为 "password" 的元素。其值最小为 5 个字符,最大为 8 个字符:

<xs:element name="password">
	<xs:simpleType>
	  <xs:restriction base="xs:string">
	    <xs:minLength value="5"/>
	    <xs:maxLength value="8"/>
	  </xs:restriction>
	</xs:simpleType>
</xs:element> 

三、Schema深入之复杂的类型

  复合元素是指包含其他元素及/或属性的 XML 元素,其包含有四种类型的复合元素:

  • 空元素
  • 包含其他元素的元素
  • 仅包含文本的元素
  • 包含元素和文本的元素

注释:上述元素均可包含属性!

  在 XML Schema 中,我们有两种方式来定义复合元素,下面以这个XML来进行举例:

<employee>
	<firstname>John</firstname>
	<lastname>Smith</lastname>
</employee>

<1> 通过命名此元素,可直接对"employee"元素进行声明

 

<xs:element name="employee">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="firstname" type="xs:string"/>
      <xs:element name="lastname" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

  假如您使用上面所描述的方法,那么仅有 "employee" 可使用所规定的复合类型。请注意其子元素,"firstname" 以及 "lastname",被包围在指示器 <sequence>中。这意味着子元素必须以它们被声明的次序出现。(指示器会在下面进行详细介绍)
<2> "employee" 元素可以使用 type 属性

  其实我们在上面已经提及了这部分,type属性的作用是引用要使用的复合类型的名称:

<xs:element name="employee" type="personinfo"/>

<xs:complexType name="personinfo">
  <xs:sequence>
    <xs:element name="firstname" type="xs:string"/>
    <xs:element name="lastname" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

  这样做的好处是任何xs:element定义的时候都可以引用name="personinfo"的这个xs:complexType。
  我们也可以在已有的复合元素之上以某个复合元素为基础,然后添加一些元素,这非常像平常说的继承关系,就像这样:

<xs:element name="employee" type="fullpersoninfo"/>

<xs:complexType name="personinfo">
  <xs:sequence>
    <xs:element name="firstname" type="xs:string"/>
    <xs:element name="lastname" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="fullpersoninfo">
  <xs:complexContent>
    <xs:extension base="personinfo">
      <xs:sequence>
        <xs:element name="address" type="xs:string"/>
        <xs:element name="city" type="xs:string"/>
        <xs:element name="country" type="xs:string"/>
      </xs:sequence>
    </xs:extension>
  </xs:complexContent>
</xs:complexType>

  其中<xs:extension base="personinfo"></xs:sequence>就是将此元素定位基础。

3.1 XSD 复合空元素

  空的复合元素不能包含内容,只能含有属性。下面是一个空的 XML 元素:

<product prodid="1345" />

  在Schema中声明此 "product" 元素如下:

<xs:element name="product">
  <xs:complexType>
    <xs:attribute name="prodid" type="xs:positiveInteger"/>
  </xs:complexType>
</xs:element>

  或者您可以为一个 complexType 元素起一个名字,然后为 "product" 元素设置一个 type 属性并引用这个 complexType 名称(通过使用此方法,若干个元素均可引用相同的复合类型):

<xs:element name="product" type="prodtype"/>
<xs:complexType name="prodtype">
  <xs:attribute name="prodid" type="xs:positiveInteger"/>
</xs:complexType>

3.2 XSD 复合类型 - 仅含元素

  XML 元素,"person",仅包含其他的元素:

<person>
	<firstname>John</firstname>
	<lastname>Smith</lastname>
</person>

  我们可以在 schema 中这样定义 "person" 元素:

<xs:element name="person">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="firstname" type="xs:string"/>
      <xs:element name="lastname" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

注意:其中使用了指示器,这意味着被定义的元素必须按上面的次序出现在 "person" 元素中。我们也可以为 complexType 元素设定一个名称,并让 "person" 元素的 type 属性来引用此名称,与上面类同,就不在举例了。

3.3 XSD 仅含文本复合元素

  仅含文本的复合元素可包含文本和属性。

  此类型仅包含简易的内容(文本和属性),因此我们要向此内容添加 simpleContent 元素。当使用简易内容时,我们就必须在 simpleContent 元素内定义扩展或限定,就像这样:

<xs:element name="某个名称">
  <xs:complexType>
    <xs:simpleContent>
      <xs:extension base="basetype">
        ....
        ....
      </xs:extension>     
    </xs:simpleContent>
  </xs:complexType>
</xs:element>

或者:

<xs:element name="某个名称">
  <xs:complexType>
    <xs:simpleContent>
      <xs:restriction base="basetype">
        ....
        ....
      </xs:restriction>     
    </xs:simpleContent>
  </xs:complexType>
</xs:element>

注意:需要使用 extension 或 restriction 元素来扩展或限制元素的基本简易类型。
示例如下:

  这里有一个 XML 元素的例子,"shoesize",其中仅包含文本:

<shoesize country="france">35</shoesize>

  下面这个例子声明了一个复合类型,其内容被定义为整数值,并且 "shoesize" 元素含有名为 "country" 的属性:

<xs:element name="shoesize">
  <xs:complexType>
    <xs:simpleContent>
      <xs:extension base="xs:integer">
        <xs:attribute name="country" type="xs:string" />
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:element>

  我们也可为 complexType 元素设定一个名称,并让 "shoesize" 元素的 type 属性来引用此名称(通过使用此方法,若干元素均可引用相同的复合类型):

<xs:element name="shoesize" type="shoetype"/>
<xs:complexType name="shoetype">
  <xs:simpleContent>
    <xs:extension base="xs:integer">
      <xs:attribute name="country" type="xs:string" />
    </xs:extension>
  </xs:simpleContent>
</xs:complexType>

3.4 XSD 带有混合内容的复合类型

  混合的复合类型可包含属性、元素以及文本。详见:http://www.w3school.com.cn/schema/schema_complex_mixed.asp

3.5 XSD 复合类型指示器

  通过指示器,我们可以控制在文档中使用元素的方式。有七种指示器:

  • Order 指示器:
    • All
    • Choice
    • Sequence
  • Occurrence 指示器:
    • maxOccurs
    • minOccurs
  • Group 指示器:
    • Group name
    • attributeGroup name

3.5.1 Order 指示器

  Order 指示器用于定义元素的顺序。
<1> All 指示器
  <all> 指示器规定子元素可以按照任意顺序出现,且每个子元素必须只出现一次:

<xs:element name="person">
  <xs:complexType>
    <xs:all>
      <xs:element name="firstname" type="xs:string"/>
      <xs:element name="lastname" type="xs:string"/>
    </xs:all>
  </xs:complexType>
</xs:element>

注:当使用 <all> 指示器时,你可以把 <minOccurs> 设置为 0 或者 1,而只能把 <maxOccurs> 指示器设置为 1

<2> Choice 指示器
  <choice> 指示器规定可出现某个子元素或者可出现另外一个子元素(非此即彼):

<xs:element name="person">
  <xs:complexType>
    <xs:choice>
      <xs:element name="employee" type="employee"/>
      <xs:element name="member" type="member"/>
    </xs:choice>
  </xs:complexType>
</xs:element>

提示:如需设置子元素出现任意次数,可将 <maxOccurs> 设置为 unbounded(无限次)。
<3> Sequence 指示器
  <sequence> 规定子元素必须按照特定的顺序出现:

<xs:element name="person">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="firstname" type="xs:string"/>
      <xs:element name="lastname" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

3.5.2 Occurrence 指示器

  Occurrence 指示器用于定义某个元素出现的频率。
注:对于所有的 "Order" 和 "Group" 指示器(any、all、choice、sequence、group name 以及 group reference),其中的 maxOccurs 以及 minOccurs 的默认值均为 1。
<1> maxOccurs 指示器
  <maxOccurs> 指示器可规定某个元素可出现的最大次数:

<xs:element name="person">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="full_name" type="xs:string"/>
      <xs:element name="child_name" type="xs:string" maxOccurs="10"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

  上面的例子表明,子元素 "child_name" 可在 "person" 元素中最少出现一次(其中 minOccurs 的默认值是 1),最多出现 10 次。
<2> minOccurs 指示器
  <minOccurs> 指示器可规定某个元素能够出现的最小次数:

<xs:element name="person">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="full_name" type="xs:string"/>
      <xs:element name="child_name" type="xs:string"
      maxOccurs="10" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

  上面的例子表明,子元素 "child_name" 可在 "person" 元素中出现最少 0 次,最多出现 10 次。
提示:如需使某个元素的出现次数不受限制,请使用 maxOccurs="unbounded" 这个声明。

3.5.3 Group 指示器

  Group 指示器用于定义相关的数批元素。

<1> 元素组
  元素组通过 group 声明进行定义:

<xs:group name="组名称">
  ...
</xs:group>

  您必须在 group 声明内部定义一个 all、choice 或者 sequence 元素。下面这个例子定义了名为 "persongroup" 的 group,它定义了必须按照精确的顺序出现的一组元素:

<xs:group name="persongroup">
  <xs:sequence>
    <xs:element name="firstname" type="xs:string"/>
    <xs:element name="lastname" type="xs:string"/>
    <xs:element name="birthday" type="xs:date"/>
  </xs:sequence>
</xs:group>

将 group 定义完毕以后,就可以在另一个定义中引用它了:

<xs:element name="person" type="personinfo"/>

<xs:complexType name="personinfo">
  <xs:sequence>
    <xs:group ref="persongroup"/>
    <xs:element name="country" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

<2> 属性组
  属性组通过 attributeGroup 声明来进行定义:

<xs:attributeGroup name="组名称">
  ...
</xs:attributeGroup>

下面这个例子定义了名为 "personattrgroup" 的一个属性组:

<xs:attributeGroup name="personattrgroup">
  <xs:attribute name="firstname" type="xs:string"/>
  <xs:attribute name="lastname" type="xs:string"/>
  <xs:attribute name="birthday" type="xs:date"/>
</xs:attributeGroup>

已定义完毕属性组之后,就可以在另一个定义中引用它了,就像这样:

<xs:element name="person">
  <xs:complexType>
    <xs:attributeGroup ref="personattrgroup"/>
  </xs:complexType>
</xs:element>

3.6 XSD <any> 元素

  <any> 元素使我们有能力通过未被 schema 规定的元素来拓展 XML 文档!换句话说,我们用<any>元素进行占位,然后就可以使用任意元素进行插入了,也就是说我们想拓展原来的元素,只需要在其位置插入<any>元素,然后在其它地方定义即可,这样既不会破坏原来的结构,也进行了相应的拓展。

详细参见:http://www.w3school.com.cn/schema/schema_complex_any.asp

3.7 XSD <anyAttribute> 元素

  <anyAttribute> 元素使我们有能力通过未被 schema 规定的属性来扩展 XML 文档!

  与上面的Any类同,只不过是一个拓展的是元素,一个拓展的是属性。

详细参见:http://www.w3school.com.cn/schema/schema_complex_anyattribute.asp

注:<any> 和 <anyAttribute> 均可用于制作可扩展的文档!它们使文档有能力包含未在主 XML schema 中声明过的附加元素。

3.8 XSD 元素替换(Element Substitution)

  通过 XML Schema,一个元素可对另一个元素进行替换。
详细参见:http://www.w3school.com.cn/schema/schema_complex_subst.asp

w3cschool提供的XSD 实例:http://www.w3school.com.cn/schema/schema_example.asp

四、Schema深入之数据类型

4.1 字符串

  字符串数据类型用于可包含字符串的值。字符串数据类型可包含字符、换行、回车以及制表符。

注:如果您使用字符串数据类型,XML 处理器就不会更改其中的值。

scheme 中字符串声明的例子:

<xs:element name="customer" type="xs:string"/>

  规格化字符串数据类型(NormalizedString Data Type):规格化字符串数据类型同样可包含字符,但是 XML 处理器会移除折行,回车以及制表符。
schema 中规格化字符串数据类型的例子:

 

<xs:element name="customer" type="xs:normalizedString"/>

  Token 数据类型(Token Data Type):Token 数据类型同样可包含字符,但是 XML 处理器会移除换行符、回车、制表符、开头和结尾的空格以及(连续的)空格。
schema 中有关 token 声明的例子:

<xs:element name="customer" type="xs:token"/>

  字符串数据类型:请注意,所有以下的数据类型均衍生于字符串数据类型(除了字符串数据类型本身)!

对字符串数据类型的限定(Restriction)
可与字符串数据类型一同使用的限定:

 

  • enumeration
  • length
  • maxLength
  • minLength
  • pattern (NMTOKENS、IDREFS 以及 ENTITIES 无法使用此约束)
  • whiteSpace

4.2 日期及时间数据类型(Date and Time Data Types)

详见:http://www.w3school.com.cn/schema/schema_dtypes_date.asp

4.3 数值类型

详见:http://www.w3school.com.cn/schema/schema_dtypes_numeric.asp

4.4 杂项数据类型(Miscellaneous Data Types)

其他杂项数据类型包括逻辑、base64Binary、十六进制、浮点、双精度、anyURI、anyURI 以及 NOTATION。

详见:http://www.w3school.com.cn/schema/schema_dtypes_misc.asp

待参考资料:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值