XML_全解串讲

XML 专栏收录该内容
5 篇文章 0 订阅

&1.XML简介
 1) XML代表可扩展的标记语言(eXtensible Markup Language);
 2) XML由W3C联盟发展维护;
 3) XML文档是一种严格规范的语言,必须按照规范来写。

XML的用途,数据传输的中间件,做为通用文档格式
1,数据交换
2,数据管理
3,充当配置文件

XML文档的框架结构
    XML文档=序言+元素+杂项(可选)
    1)序言
        序言=(XML声明)+(杂项)+(文档类型声明)
        XML声明
            <? xml版本信息 (编码信息) (文档独立性信息) ?>
        如:<?xml version="1.0" encoding="gb2312" standalone="yes"?>
        文档类型声明
            规定元素的结构和属性列表的取值
        如:<!DOCTYPE studinfo SYSTEM "studinfo.dtd">
    2)元素
        空元素
            <空元素标签名 属性="属性值"/>
            <student sid="1"/>
            <student sid="1"></student>
        非空元素
            <起始标签>内容<结束标签>
            内容=(子元素|字符数据|字符数据段|引用|处理指令)*
            字符数据   
                字符数据中,不能含有  < > " ' &

                字符转义
                &lt; 代表 <
                &gt; 代表 >
                &quot; 代表双引号 "
                &apos; 代表单引号 '
                &amp; 代表 &
            字符数据段
                <![CDATA[字符数据]]>
                字符数据段,不解析,所见即所得
                <!CDATA[........]>的部分不必使用转义,其中内容会直接输出。
            引用
                <!ENTITY 引用名 ".......">   
                实体声明
                <!ENTITY 引用名 "......">
                使用实体,引用
                &引用名
    3)杂项
        处理指令
            XML为其它应用程序准备的接口。
            <?处理指令?>
        注释<!-- 注释内容 -->
        空白符指空格、回车等
 
eg:
    <?xml verson="1.0"?><!--这一句一定要求写在文件的第一行-->
    <!--只能有一个根元素-->
    <!--xml文档是由标签和标签中的内容组成的,标签和标签中的内容合成为元素-->
    <root><!--根标签-->
        <!--根元素的内容-->
        <leaf>
            <!--子元素-->
        <leaf>
    </root>

eg:
    <?xml version="1.0" encoding="gb2312"?>(XML文件的声明)
    <!--this is a comment hehe-->(注释)
    <student>(根元素)
        <script>(子元素)
        <![CDATA[function compare(a,b){
            if(a>b)
                then {return 1}
            else{return 0}
            }]]>
        </script>
        <script value="java"/>(空元素)
        <script value="java"></script>(空元素)
        <name country="china" (属性名=“属性值”)>张三</name>
    </student>

格式良好的XML文档的规范
1)文档声明位于文件的开头<?xml verson="1.0"?> 而且一定要写
2)文档中只能定义一个唯一的根元素(根元素是在文档声明之后的最外层的元素)
3)标签必须闭合,且不能交叉,有元素的起始标签,就必须有其结束标签(空元素除外)
    <a>
    <b>
    </a>
    </b>
4)大小写敏感,起始标签和结束标签的名字要一致
    <student>xxx</STUDENT>
5)属性值必须用引号引起来
    <student name="illu"/>
6)注意特殊字符,使用时需要使用转义字符。 < > " ' &


&2.DTD(结构定义)
DTD文档是用于规定XML文档的结构。只有结构符合所引用的DTD文件的XML文件才能称之为有效的XML文件。

DTD(文档类型定义)
!DOCTYPE 定义DTD文件名
!ELEMENT 定义元素中可用的数据类型
#PCDATA 可解析字符串。

1)DTD的调用
方式一:调用内部文档类型定义。
    <?xml version="1.0" standalone="yes"?>
    <!DOCTYPE studinfo[<!ELEMENT studinfo (#PCDATA)>]>
    <studinfo>
    </studinfo>
    注意点:
    (1) studinfo与(#PCDATA)有空格
    (2) standalone="yes"

方式二:调用外部文档类型定义,需要写一个DTD文档
    <?xml version="1.0" standalone="no"?>
    <!DOCTYPE studinfo SYSTEM "studinfo1.dtd">
    <studinfo>
    </studinfo>
    注意点:
    (1)standalone="no"
    (2)注意dtd文件的路径

2)DTD的结构
   
1.元素类型声明
    指明元素的名称和元素含有的内容。
    元素类型声明=<!ELEMENT 元素名 (元素内容说明)>
    元素内容说明='EMPTY'|'ANY'|混合内容|元素内容|'#PCDATA'
    #PCDATA:
    只有可析的字符数据才能作为元素的内容
       
    元素内容:
    元素内部只能出现指定的子元素

    事例:带有子元素的元素结构定义
    <!ELEMENT studinfo (name,age,course+,interest*,gendar?)>

    sequence <!ELEMENT name (a,b)>
    a b 必须顺序出现
    choice <!ELEMENT name (a|b)>
    a b 二者必须出现一个
    one <!ELEMENT name (a)>
    a 必须出现一次也只能出现一次
    one or more <!ELEMENT name (a)+>
    a 必须出现一次或多次
    zero or more<!ELEMENT name (a)*>
    a 可以不出现或出现多次
    one or zero<!ELEMENT name (a)?>
    a 可以不出现或出现一次
   
    <!ELEMENT studinfo (age|brithday)>
    Enumerated:枚举类型,由“|”分隔的可能的子元素,在可能出现的子元素中只能有一个出现。

    EMPTY:元素内容为空时才写(空元素,其中不能有内容)
    <!ELEMENT studinfo EMPTY>(无子元素)
    <studinfo></studinfo>
    <studinfo/>
    ANY:二者选一,要不是文本 要不是子元素
    <!ELEMENT studinfo ANY>
    <studinfo></studinfo>
    <studinfo>zhangsan</studinfo>
    <studinfo>
        <name>xxx</name>
    </studinfo>

    混合内容:标记文本和可析字符串

   

2.元素属性表声明
    属性:由“=”分隔的成对的属性名和属性值构成,只能出现在元素标记的内部。
            结束标记不能带属性,一个元素可以具有多个属性
    语法:<!ATTLIST 对应的元素名 属性名 属性取值类型 属性默认值>
    属性取值类型
    1、CDATA:可析字符
    2、Enumerated:枚举类型,由“|”分隔的可能的属性值列表
    属性默认值:
    注意
    1、#REQUIRED:必须提供属性值
    2、#IMPLIED:可提供也可不提供
    3、#FIXED:不能修改 写就有 不写就没有
    事例:
    <!ELEMENT studinfo (#PCDATA)>
    <!ATTLIST studinfo grade CDATA "grade1">
    <!ATTLIST studinfo name CDATA #REQUIRED>
    <!ATTLIST studinfo sex CDATA #IMPLIED>
    <!ATTLIST studinfo school CDATA #FIXED "beida">
    <!ATTLIST studinfo interest (fish|play|read) "fish" >

    <?xml version="1.0" standalone="no"?>
    <!DOCTYPE studinfo SYSTEM "studinfo5.dtd">
    <studinfo name="zhangshan" sex="girl" school="beida" interest="play" >
        zhangshan
    </studinfo>
   
    实体声明
    实体:存储了任意符合规则的xml文档单元片断。
    1、内部通用实体
    定义格式 <!ENTITY 实体名 “实体内容”>
    引用格式 &实体名;

    2、外部通用实体
    定义格式 <!ENTITY 实体名 SYSTEM “外部实体的URI”>
    引用格式  &实体名;
    事例:
    in schoolinfo.ent
    <?xml version="1.0" encodeing="UTF-8"?>
    Tarena Xian

    in studinfo.xml
    <?xml version="1.0" standalone="no"?>
    <!DOCTYPE studinfo[
    <!ELEMENT studinfo (name,age,address,school)>
    <!ELEMENT name (#PCDATA)>
    <!ELEMENT age (#PCDATA)>
    <!ELEMENT address (#PCDATA)>
    <!ELEMENT school (#PCDATA)>
    <!ENTITY schoolinfo SYSTEM "schoolinfo.ent"><!--外部实体的定义-->
    ]>
    <studinfo>
        <name>zhangshan</name>
        <age>20</age>
        <address>beijing haidian</address>
        <school>&schoolinfo;</school><!--实体的使用-->
    </studinfo>
   
    记号声明
    用记号标识不可解析的数据
    定义格式 <!NOTATION 记号名 SYSTEM "外部标识URI">
    <!NOTATION jpeg SYSTEM "photoshop.exe">
    <!NOTATION gif SYSTEM "photoshop.exe">
    <!ELEMENT person (#PCDATA)>
    <!ATTLIST person picformat NOTATION (jpeg|gif) #REQUIRED>

    <person picformat="jpeg">KELLY BROWN</person>

    3)DTD的缺陷
        a.DTD不是一个XML格式的文档
        b.DTD粗线条的定义,有一些约束在DTD中是表达不了的
        c.DTD不支持命名空间,解析器无法测试命名空间。

&3.NameSpace(命名空间)
namespace是为了解决XML文档中的命名冲突问题的。
1、作用:
    解决XML文档中命名冲突的问题,即将
    XML文档与引用URI标识的名域相结合,来
    限定其中的元素和属性名。
    示例:
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <teacher>
        <name>t1</name>
        <sex>man</sex>
        <student>
        <name>s1</name><!--这个name和teacher根元素中的name发生命名冲突-->
        <sex>girl</sex><!--这个sex和teacher根元素中的sex发生命名冲突-->
        </student>
    </teacher>
       
2、名域的声明

(1)直接定义
    <elementName xmlns:prefix='URI'/>
    xmlns:名域前缀="名域的URI"(唯一性)
    类比:名字与身份证
    名域的使用,名域前缀:需要限定的元素名
    示例:
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <teacher:teacher xmlns:teacher="http://www.tarena.com/teacher"
            xmlns:student="http://www.tarena.com/student">
        <teacher:name>zhangshan</teacher:name>
        <teacher:sex>man</teacher:sex>
        <teacher:student>
            <student:name>stu1</student:name>
            <student:sex>girl</student:sex>
        </teacher:student>
    </teacher:teacher>

(2)缺省定义
    xmlns=名域的URI
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <teacher xmlns="http://www.tarena.com/teacher"
        xmlns:student="http://www.tarena.com/student">
        <name>zhangshan</name>
        <sex>man</sex>
        <student>
            <student:name>stu1</student:name>
            <student:sex>girl</student:sex>
        </student>
    </teacher>

3、名域的使用
    (1)用名域限定元素
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <teacher:teacher xmlns:teacher="http://www.tarena.com/teacher"
                xmlns:student="http://www.tarena.com/student">
        <teacher:name>zhangshan</teacher:name>
        <teacher:sex>man</teacher:sex>
        <teacher:student>
            <student:name>stu1</student:name>
            <student:sex>girl</student:sex>
        </teacher:student>
    </teacher:teacher>
    (2)用名域限定属性
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <teacher:teacher xmlns:teacher="http://www.tarena.com/teacher"
                    xmlns:student="http://www.tarena.com/student">
        <teacher:name>zhangshan</teacher:name>
        <teacher:sex>man</teacher:sex>
        <teacher:address teacher:city="beijing">caoyang,no1</teacher:address>
        <teacher:student>
            <student:name>stu1</student:name>
            <student:sex>girl</student:sex>
            <student:address student:city="tianjin">haidian,no2</student:address>
        </teacher:student>
    </teacher:teacher>

4、名域的作用范围
名域能够把声明它的元素和该元素的所有子元素关联起来,除非它们被其他的名域声明所覆盖。

&XML Schema

Schema 也是XML文档,用于定义XML文档的结构。
目标名域
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
使用目标名域中的限制,要只用这个schema文件结构生成XML文档中必须使用者个默认名域。

schema文件的扩展名为 .xsd schema文档的语法和XML的语法相同。
schema文档也有根元素,根元素为schema。

<element 元素名 name="值" type(类型)="类型名"> 参照类型约束,来约束元素的内容
元素的默认和固定值   
1) 简单元素可以有一个默认或固定值:   
2) 当没有指定值时,一个默认的值自动分配给元素。
在这个例子中,默认值为red:<xs:element name="color" type="xs:string" default="red"/>
3) 一个固定值也是自动分配给元素的,你不能指定其它值。
在这个例子中,默认值为red:<xs:element name="color" type="xs:string" fixed="red"/>

ref关键字 参照定义。

属性结构的定义,属性也可以使用固定值或者是默认值
<xs:attribute name=".." type=".." use="..."></xs:attribute>

schema文件中也可以定义元素结构和类型,schema文件中对元素内容加以限制

<xs:choice><!--只能选择其子元素中之一,类似于枚举-->
    <xs:element name="mother" type="xs:string"/>
    <xs:element name="father" type="xs:string"/>
</xs:choice>

<xs:sequence><!--这个标签的功能是定义了name元素的结构-->
    <xs:element name="firstname" type="xs:string"/>
    <!--name元素必须有名为firstname的子元素-->
    <xs:element name="lastname" type="xs:string"/>
    <!--name元素必须有名为lastname的子元素-->
</xs:sequence>

schema中可以定义元素内容类型
1. 简单类型
2. 自定义类型,复杂类型,子元素组合
           简单类型,基本类型加限制

simpleType:简单类型定义
restriction:基本类型引用
enumeration:使用枚举类型,从给定值中选择且必选其一。
minInclusive:简单类型加最小值约束,且包含设定的最小值
maxExclusive:简单类型加最大值约束,且包含设定的最大值

以下是其使用的事例

. 简单类型加限制

只能使用非负整数3到7包含3和7。
<xs:simpleType name="qType">
    <xs:restriction base='xs:integer'>
    <xs:minIncusive='3'/><!--包含设定的最小值-->
    <xs:maxIncusive='7'/><!--包含设定的最大值-->
    </xsrestruction>
</xs:simpleType>

. 复杂类型定义

<xs:complexType><!--这个标签是用于定义混合类型的-->
    <xs:sequence><!--这个标签的功能是定义了name元素的结构-->
        <xs:element name="firstname" type="xs:string"/>
        <!--name元素必须有名为firstname的子元素-->
        <xs:element name="lastname" type="xs:string"/>
        <!--name元素必须有名为lastname的子元素-->
    </xs:sequence>
</xs:complexType>

复杂类型定义事例:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.ibm.com" xmlns:test="http://www.ibm.com">
    <element name='x' type="xtype">
    </element>
    <complexType name="xtype">
        <simpleContent>
            <extension base='string'>
                <attribute name='a' type="atype" />
            </extension>
        </simpleContent>
    </complexType>
    <simpleType name="atype">
        <restriction base='integer'>
            <minInclusive value='10' />
            <maxInclusive value='20' />
        </restriction>
    </simpleType>
</schema>


整体schema文档事例
演示simpleType用法,即自定义类型
学生(id = "1000")
    姓名
    年龄(必须是int,并且只能取一定范围的值)
    父亲(父母二者选一)
    母亲
    专业(枚举类型)
知识点:
    simpleType
    restriction
    enumeration
    minInclusive
    maxExclusive

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:element name="student">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="name"/><!--参照name元素的定义-->
                <xs:element ref="age"/><!--参照age元素的定义-->
                <xs:choice><!--只能选择其子元素中之一,类似于枚举-->
                    <xs:element name="mother" type="xs:string"/>
                    <xs:element name="father" type="xs:string"/>
                </xs:choice>
                <xs:element name="speciality" type="specialType"/>
            </xs:sequence>
            <xs:attribute name="id" type="xs:string" use="required"/>
        </xs:complexType>
        <xs:element name="name">
            <xs:complexType><!--这个标签是用于定义混合类型的-->
                <xs:sequence><!--这个标签的功能是定义了name元素的结构-->
                    <xs:element name="firstname" type="xs:string"/>
                    <!--name元素必须有名为firstname的子元素-->
                    <xs:element name="lastname" type="xs:string"/>
                    <!--name元素必须有名为lastname的子元素-->
                </xs:sequence>
            </xs:complexType>
        </xs:element>
        <xs:element name="age" type="ageArea"/>
            <xs:simpleType name="specialType">
                <xs:restriction base="xs:string">
                    <xs:enumeration value="computer"/>
                    <xs:enumeration value="english"/>
                </xs:restriction>
            </xs:simpleType>
            <xs:simpleType name="ageArea"><!--简单类型加限制-->
                <xs:restriction base="xs:int">
                    <xs:minInclusive value="10"/>
                    <xs:maxExclusive value="30"/>
                </xs:restriction>
            </xs:simpleType>
        </xs:element>
    </xs:element>
</xs:schema>

针对以上schema文件的有效的XML文件事例

<?xml version="1.0" encoding="UTF-8"?>
<!--
演示simpleType用法,即自定义类型
学生(id = "1000")
    姓名
    年龄(必须是int,并且只能取一定范围的值)
    父亲(父母二者选一)
    母亲
    专业(枚举类型)
-->
<student xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="C:\Program Files\Altova\XMLSpy2006\testofczh\exec\student5.xsd" id="1000">
    <name>
        <firstname>shang</firstname>
        <lastname>zhang</lastname>
    </name>
    <age>30</age>
    <father>lishi</father>
    <speciality>computer</speciality>

</student>


XML文档的解析

SAX:事件机制驱动。在遇到相应的节点时,会发出一个事件,当解析器发现元素开始、元素结束、文本、文档的开始或结束等时,发送事件,程序员编写响应这些事件的代码,保存数据。
  优点:
        不用事先调入整个文档,占用资源少,
        SAX解析器代码比DOM解析器代码小。
  缺点:
        不是持久的;事件过后,若没保存数据,那么数据就丢了,比较消耗时间,
        只能顺序处理,不能选择读取。不支持文档的创建和修改,
        无状态性;从事件中只能得到文本,但不知该文本属于哪个元素。
  使用场合:Applet;只需XML文档的少量内容,很少回头访问;机器内存少

SAX处理流程
<?xml version="1.0"?>
<samples>
   <server>UNIX</server>
   <monitor>color</monitor>
</samples>

分析这个代码片断的 SAX 处理器一般情况下将产生以下事件:

Start document
Start element (samples)
Characters (white space)
Start element (server)
Characters (UNIX)
End element (server)
Characters (white space)
Start element (monitor)
Characters (color)
End element (monitor)
Characters (white space)
End element (samples)

SAX API 允许开发人员捕捉这些事件并对它们作出反应。

SAX 处理涉及以下步骤:

创建一个事件处理程序。
创建 SAX 解析器。
向解析器分配事件处理程序。
解析文档,同时向事件处理程序发送每个事件。

要实现SAX解析XML文档,有两种方法,

XMLReader和XMLReaderFactory
XMLReader read=XMLReaderFactory.createXMLReader();生成XMLReader对象,使用XMLReader对象的方法parse(File f,ContentHandler handler),ContentHandler是一个定义好事件处理方法的接口,DTDHandler ,EntityResolver ,ErrorHandler这三个接口和 ContentHandler接口相同,但是其中定义的是其他事件处理方法,一般只是实现ContentHandler接口。

使用SAX解析XML文档,需要先有SAXParserFactory对象,他的对象是通过自身的静态方法newInstance(),然后再通过SAXParserFactory对象来创建SAXParser对象,使用SAXParser对象的
parse(File f,DefaultHandler handler),DefaultHandler是用来处理解析时发出的事件的类,就可以进行解析。
DefaultHandler实现了ContentHandler,DTDHandler ,EntityResolver ,ErrorHandler,四个接口,但是只给出了空实现,便于使用者覆盖相应的方法。

SAX解析的其他方法请参阅JAVA API文档。(javax.xml.parsers ,org.xml.sax ,org.xml.sax.helpers)


DOM (文档对象模型)Document Object Modle
为 XML 文档的已解析版本定义了一组接口。解析器读入整个文档,然后构建一个驻留内存的树结构,然后代码就可以使用 DOM 接口来操作这个树结构。
    优点:整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能;
    缺点:将整个文档调入内存(包括无用的节点),浪费时间和空间;
    使用场合:一旦解析了文档还需多次访问这些数据;硬件资源充足(内存、CPU)

DOM解析是将整个的XML文档元素结构读入内存,由根元素向下形成子元素分级树状关系。

DOM的解析

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(name);
以上三行代码,使用来生成Document对象的,Document对象就代表了读入内存后结构化的XML文档。
使用Document对象的getDocumentElement()方法获得子节点,可以通过不断的迭代便利所有节点,这些节点就代表了元素,从根元素开始一直到最内层的子元素。
getElementsByTagName(String tagname) 这个方法可以通过元素的名来或得该元素内层元素,也就是或得了这个节点的所有子节点(NodeList)NodeList的方法getLength()(列表中的节点数),通过循环使用 Node item(int index) (返回集合中的第 index 个项)方法,来获得每个子节点。

DOM解析的其他方法请参阅JAVA API文档。(org.w3c.dom)

 

DOM4j,JDOM

开源的XML文档解析器,实现DOM,SAX接口,保留了DOM和SAX的基本语法,对解析性能进行了优化。

JDOM
需要jdom.jar和

JDOM的背后使用的是使用SAX对文件进行扫描的。
SAXBuilder builder=new SAXBuilder();//创建解析器
使用SAX扫描之后的结果保存成DOM结构的树。JDOM对解析过程作了简化。
JDOM中的方法便的更加易用。例如:getRootElement(),getChildren("...")方法的返回值是java.util.List类型,getText()方法直接可以返回元素中的内容,他的返回值类型是String类型。

JDOM也可以对XML文档进行写操作。
XMLOutputter类的对象可以向文件中写信息,setEncoding("")设置内码,setNewLine(true),设置换行。output(Document  docFileWriter write)方法可以向文件中写入。


DOM解析流程
(1)得到DOM解析器的工厂实例  
  DocumentBuilderFactory domfac=DocumentBuilderFactory.newInstance();  
  得到javax.xml.parsers.DocumentBuilderFactory;类的实例就是我们要的解析器工厂  
(2)从DOM工厂获得DOM解析器  
  DocumentBuilder dombuilder=domfac.newDocumentBuilder();  
  通过javax.xml.parsers.DocumentBuilderFactory实例的静态方法newDocumentBuilder()得到DOM解析器
(3)把要解析的XML文档转化为输入流,以便DOM解析器解析它
  InputStream is=new FileInputStream("bin/library.xml");
   
(4)解析XML文档的输入流,得到一个Document
  Document doc=dombuilder.parse(is);
  由XML文档的输入流得到一个org.w3c.dom.Document对象,以后的处理都是对Document对象进行的
(5)得到XML文档的根节点
  Element root=doc.getDocumentElement();
  在DOM中只有根节点是一个org.w3c.dom.Element对象。
(6)得到节点的子节点
  NodeList books=root.getChildNodes();
    for(int i=0;i<books.getLength();i++){
        Node book=books.item(i);
    }
  这是用一个org.w3c.dom.NodeList接口来存放它所有子节点的,还有一种循环子节点的方法,
    for(Node node=root.getFirstChild(); node!=null; node=node.getNextSibling()){
        //。。。
    }
(7)取得节点的属性值
  String email=book.getAttributes().getNamedItem("email").getNodeValue();
  System.out.println(email);
  注意,节点的属性也是它的子节点。它的节点类型也是Node.ELEMENT_NODE

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

iteye_16969

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值