XSLT 1.0推荐标准摘译(第四部分)

8 重复

<!-- Category: instruction -->
<xsl:for-each
  select = node-set-expression>
  <!-- Content: (
xsl:sort *, template) -->
</xsl:for-each>

必要属性select 中的表达式计算结果必须是一个节点集。比如XML 文档:

<customers>

  <customer>

    <name>...</name>

    <order>...</order>

    <order>...</order>

  </customer>

  <customer>

    <name>...</name>

    <order>...</order>

    <order>...</order>

  </customer>

</customers>

下例将遍历每个客户生成一张表:

<xsl:template match="/">

  <html>

    <head>

      <title>Customers</title>

    </head>

    <body>

      <table>

        <tbody>

          <xsl:for-each select="customers/customer">

            <tr>

              <th>

                <xsl:apply-templates select="name"/>

              </th>

              <xsl:for-each select="order">

                <td>

                  <xsl:apply-templates/>

                </td>

              </xsl:for-each>

            </tr>

          </xsl:for-each>

        </tbody>

      </table>

    </body>

  </html>

</xsl:template>

 

9 条件处理

9.1 xsl:if

<!-- Category: instruction -->
<xsl:if
  test = boolean-expression>
  <!-- Content: template -->
</xsl:if>

Test 属性值是一个表达式,计算结果转化成布尔值;如果为真则实例化内容模板,否则什么也不做,下例将names 元素中的名字生成一个逗号分隔的列表:

<xsl:template match="namelist/name">

  <xsl:apply-templates/>

  <xsl:if test="not(position()=last())">, </xsl:if>

</xsl:template>

下例将表格每隔一行用黄色显示:

<xsl:template match="item">

  <tr>

    <xsl:if test="position() mod 2 = 0">

       <xsl:attribute name="bgcolor">yellow</xsl:attribute>

    </xsl:if>

    <xsl:apply-templates/>

  </tr>

</xsl:template>

9.2 xsl:choose

<!-- Category: instruction -->
<xsl:choose>
  <!-- Content: (
xsl:when +, xsl:otherwise ?) -->
</xsl:choose>

<xsl:when
  test = boolean-expression>
  <!-- Content: template -->
</xsl:when>

<xsl:otherwise>
  <!-- Content: template -->
</xsl:otherwise>

处理xsl:choose 元素的时候,依次测试每个xsl:when ,只有第一个test 属性表达式求值结果为真的when 的内容模板被实例化;如果都不为真,则实例化otherwise 的内容模板;如果没有otherwise 模板则什么也不创建。比如下例根据有序列表的嵌套深度选择不同的编号格式:

<xsl:template match="orderedlist/listitem">

  <fo:list-item indent-start='2pi'>

    <fo:list-item-label>

      <xsl:variable name="level"

                    select="count(ancestor::orderedlist) mod 3"/>

      <xsl:choose>

        <xsl:when test='$level=1'>

          <xsl:number format="i"/>

        </xsl:when>

        <xsl:when test='$level=2'>

          <xsl:number format="a"/>

        </xsl:when>

        <xsl:otherwise>

          <xsl:number format="1"/>

        </xsl:otherwise>

      </xsl:choose>

      <xsl:text>. </xsl:text>

    </fo:list-item-label>

    <fo:list-item-body>

      <xsl:apply-templates/>

    </fo:list-item-body>

  </fo:list-item>

</xsl:template>

 

10 排序

<xsl:sort
  select = string-expression
  lang = { nmtoken }
  data-type = { "text" | "number" | qname-but-not-ncname }
  order = { "ascending" | "descending" }
  case-order = { "upper-first" | "lower-first" } />

排序xsl:sort 元素可以出现在xsl:apply-templatesxsl:for-each 中,xsl:sort 的第一个孩子指定排序主键,第二个指定次重要键,依次类推。如果xsl:apply-templatesxsl:for-each 元素中出现一个或多个xsl:sort ,则不再按照文档序处理选中的节点,而是根据指定的键排列节点然后依次处理。如果用在xsl:for-each 元素中, xsl:sort 必须是第一个孩子。xsl:apply-templatesxsl:for-each 实例化模板的时候,当前节点列表包括经过排序的所有待处理节点。

属性select 的值是一个表达式,处理每个节点的时候,以处理的节点为当前节点、没有排序的全部待处理节点作为当前节点列表对这个表达式求值,结果转化为字符串,作为该节点的排序键。Select 属性的默认值为. ,即以当前节点的字符串值作为排序键。

其他属性作为属性值模板处理,用于控制排序。Order 指定按升序(ascending )还是降序(descending )排序。Lang 说明按什么语言排序,默认由系统环境决定。data-type 指定字符串的类型:text 表示按照lang 语言习惯的词典序排序,number 说明要转化成数字进行排序,此时不再考虑lang 属性;如果采用其他数据类型也可指定一个QName ;默认值为textcase-order 取值 upper-first lower-first ,表明text 类型的键按照大写字母还是小写字母在前。

比如:

<employees>

  <employee>

    <name>

      <given>James</given>

      <family>Clark</family>

    </name>

    ...

  </employee>

</employees>

可采用下列模板规则:

<xsl:template match="employees">

  <ul>

    <xsl:apply-templates select="employee">

      <xsl:sort select="name/family"/>

      <xsl:sort select="name/given"/>

    </xsl:apply-templates>

  </ul>

</xsl:template>

 

<xsl:template match="employee">

  <li>

    <xsl:value-of select="name/given"/>

    <xsl:text> </xsl:text>

    <xsl:value-of select="name/family"/>

  </li>

</xsl:template>

11 变量和参数

<!-- Category: top-level-element -->
<!-- Category: instruction -->
<xsl:variable
  name = qname
  select = expression>
  <!-- Content: template -->
</xsl:variable>

<!-- Category: top-level-element -->
<xsl:param
  name = qname
  select = expression>
  <!-- Content: template -->
</xsl:param>

变量是绑定某个值的名称,绑定的值可以是表达式能够返回的任何对象。绑定变量可使用xsl:variablexsl:param 元素,差别在于为xsl:param 变量指定的值仅仅是一个默认值,引用参数额模板或样式表被调用时,可使用传递的参数代替默认值。变量绑定元素在样式表树中都有一定的可见区域,在该区域中,对于变量绑定元素本身可见的任何变量绑定都是不可见的,就是说只有最内层的变量可见。

11.1 结果树片段

除了四种基本XPath 数据类型(字符串、数字、Boolean 和节点集)之外,变量为表达式语言引入了一种新的数据类型:结果树片段。结果树片段表示结果树的一部分,相当于只有一个根节点的节点集,但是只允许字符串操作,而不能使用///[] 运算符。结果树片段复制到结果树中的时候,所有节点全部复制。只有引用结果树片段类型的变量,或者调用返回结果树片段类型的扩展函数、请求返回结果树片段类型的系统属性,表达式才会返回这种类型的值。

 

11.2 变量和参数的值

为变量绑定元素赋值有三种方式:select 属性(此时元素的内容必须为空)、指定元素内容模板(没有select 属性,变量的值为模板实例化得到的结果树片段)或者取默认值空字符串(没有select 和内容模板)。如果使用内容模板,则结果树片段中的节点不能有属性和名称空间节点,结果树片段中节点的基准URI 即变量绑定元素的基准URI

如果使用变量引用节点位置,不能用:

<xsl:variable name="n">2</xsl:variable>...

<xsl:value-of select="item[$n]"/>

因为变量n 绑定的是一个结果树片段,而不是数字,上述模板将输出第一个item 元素的值。可改为下面的形式:

<xsl:variable name="n" select="2"/>...

<xsl:value-of select="item[$n]"/>

或者

<xsl:variable name="n">2</xsl:variable>...

<xsl:value-of select="item[position()=$n]"/>

下面的模板将参数值指定为空节点集:

<xsl:param name="x" select="/.."/>

 

11.3 xsl:copy-of 中使用变量和参数

<!-- Category: instruction -->

<xsl:copy-of  select = expression />

xsl:value-of 首先转换成字符串不同, xsl:copy-of 元素直接将结果树片段插入结果树。如果必要属性select 表 达式计算的结果是一个结果树片段,则将整个片段复制到结果树中。如果是一个节点集,则将所有节点按照文档顺序插入结果树:元素节点的复制包括名称空间节 点、属性节点、孩子结点以及该元素本身;根节点的复制包括所有的孩子但不包括它自身。如果结果既不是结果树片段也不是节点集,则转化成字符串插入结果树。

 

11.4 顶层变量和参数

顶层变量绑定声明的是全局变量,到处可见。顶层xsl:param 元素为样式表本身声明参数,但XSLT 本身没有定义向样式表传递参数的机制。样式表不能包含相同导入优先级的同名变量绑定。定义变量值的表达式或者模板计算时,上下文节点即处理根节点时所用的上下文节点,当前节点即源文档的根节点,当前节点列表仅包含根节点。如果全局变量的值引用另一个变量,应避免循环引用。

<xsl:variable name="para-font-size">12pt</xsl:variable>

 

<xsl:template match="para">

  <fo:block font-size="{$para-font-size}">

   <xsl:apply-templates/>

  </fo:block>

</xsl:template>

 

11.5 模板中的变量和参数

在模板中,xsl:variable 可以出现在任何允许指令的地方,xsl:param 只能出现在xsl:template 的开始位置。绑定对其后的兄弟及其后代都是可见的,但对于变量绑定元素本身不可见。同一模板中的变量绑定不能同名,但可以使用相同的名称覆盖(上层模板或?)顶层的变量绑定。为便于批处理方式处理器的实现,变量一经绑定,其值不再改变。

 

11.6 向模板传递参数

<xsl:with-param  name = qname select = expression>
   <!-- Content: template -->
</xsl:with-param>

元素xsl:with-param 用于向模板传递参数,可用于xsl:call-templatexsl:apply-templates 。属性name 指定要替换其默认值的参数名称,没有匹配参数名的xsl:with-param 将被忽略。赋值的方法和变量绑定相同,计算select 表达式的上下文和模板调用元素xsl:apply-templatesxsl:call-template 相同。

<xsl:template name="numbered-block">

  <xsl:param name="format">1. </xsl:param>

  <fo:block>

    <xsl:number format="{$format}"/>

     <xsl:apply-templates/>

  </fo:block>

</xsl:template>

 

<xsl:template match="ol//ol/li">

  <xsl:call-template name="numbered-block">

    <xsl:with-param name="format">a. </xsl:with-param>

  </xsl:call-template>

</xsl:template>

 

12 其它函数

12.1 多个源文档

Function: node-set document (object , node-set ?)

Document 函数用于访问主源文档之外的XML 文档。

如果第一个参数不是节点集,则转化成字符串作为文档URI ,检索文档并构造源树。如果URI 不包含片段标识符,则返回的节点集中仅包含文档的根节点,否则返回片段标识符所指定的节点。

When the document function has exactly one argument and the argument is a node-set, then the result is the union, for each node in the argument node-set, of the result of calling the document function with the first argument being the string-value of the node, and the second argument being a node-set with the node as its only member. When the document function has two arguments and the first argument is a node-set, then the result is the union, for each node in the argument node-set, of the result of calling the document function with the first argument being the string-value of the node, and with the second argument being the second argument passed to the document function.

URI 引用是相对的。使用第二个参数node-set 中第一个节点的基准 URI 来解析绝对URI 。如果没有第二个参数,则默认为样式表中调用document 函数的那个节点。document("") 引用样式表的根节点。

Two documents are treated as the same document if they are identified by the same URI. The URI used for the comparison is the absolute URI into which any relative URI was resolved and does not include any fragment identifier. One root node is treated as the same node as another root node if the two nodes are from the same document. Thus, the following expression will always be true:

generate-id(document("foo.xml"))=generate-id(document("foo.xml"))

The document function gives rise to the possibility that a node-set may contain nodes from more than one document. With such a node-set, the relative document order of two nodes in the same document is the normal document order defined by XPath [XPath] . The relative document order of two nodes in different documents is determined by an implementation-dependent ordering of the documents containing the two nodes. There are no constraints on how the implementation orders documents other than that it must do so consistently: an implementation must always use the same order for the same set of documents.

12.2

Key 用于隐含交叉索引。XML 中的IDIDREFIDREFS 属性用于对XML 文档进行显式的交叉索引,XSLT 提供了XPath id 函数来访问这些属性。但这种机制有不少局限性:ID 属性必须在DTD 中声明,如果采用外部DTD ,只有读入的时候才能识别;一个文档只能包含一组彼此不同的ID ;元素ID 只能作为属性指定;ID 只能是XML 名,不能包含空格;一个元素最多只能有一个ID 。因此有时候XML 文档采用其他的交叉索引结构。

一个key 是一个三元组:节点、键的名称和键值(字符串)。键是ID 的推广,但没有ID 的局限。在样式表中使用xsl:key 元素声明,命名键的值可以在任何适当的地方指定,比如属性、孩子或内容,使用XPath 表达式赋值,键值可以是任何字符串。同一个节点可有多个键,这些键甚至可以同名但值不同。同一个文档中可有多个键名、键值都相同但属于不同节点的键。

<!-- Category: top-level-element -->

<xsl:key  name = qname match = pattern use = expression />

属性name 指定键名,必须是一个QName 。属性match 是一个模式,与其匹配的任何节点都可拥有该键。属性use 是一个表达式,对和模式匹配的每个节点计算一次,将结果作为键值。如果结果是节点集,则该节点拥有多个同名的键,每个键的值分别是节点集中每个节点的字符串值;否则结果转化成字符串作为键值。因此,如果节点x 有一个键y ,值为z ,则必须存在一个xsl:key 元素:

x xsl:keymatch 属性匹配;

xsl:key 元素属性name 的值为y

如果use 属性以x 为当前节点、仅含x 的节点列表为当前节点列表,计算得到对象u ,则z 等于u 转化成字符串的值,或者等于u 中每个节点的字符串值。

如果节点和多个xsl:key 元素匹配,所有匹配的xsl:key 元素都会使用。属性usematch 不能包含变量引用。

Function: node-set key (string, object)

第一个参数指定了键的名称。如果第二个参数是节点集以外的类型则转化成字符串作为键值,返回文档中具有该键且键值为这个字符串的所有节点组成的节点集。如果第二个参数是节点集,相当于指定了多个键值(彼此为或的关系)。

比如,对于声明<xsl:key name="idkey" match="div" use="@id"/> ,表达式 ("idkey",@ref) 相当于id(@ref) ,假设XML 源文档中声明了唯一的ID 属性<!ATTLIST div id ID #IMPLIED> 而且当前节点的ref 属性没有空格。

假一个描述函数库的文档使用prototype 元素定义函数:

<prototype name="key" return-type="node-set">

<arg type="string"/>

<arg type="object"/>

</prototype>

并且有一个function 元素引用函数名:

<function>key</function>

可用下面的样式表在引用和定义之间建立超链接:

<xsl:key name="func" match="prototype" use="@name"/>

 

<xsl:template match="function">

<b>

  <a href="#{generate-id(key('func',.))}">

    <xsl:apply-templates/>

  </a>

</b>

</xsl:template>

 

<xsl:template match="prototype">

<p><a name="{generate-id()}">

<b>Function: </b>

...

</a></p>

</xsl:template>

还可使用key 检索其它文档中的键。比方说,假设文档中有形如<bibref>XSLT</bibref> 的参考资料引用,而另一个XML 文档bib.xml 则包含资料记录<entry name="XSLT">...</entry> ,可用下面的样式表转换bibref 元素:

<xsl:key name="bib" match="entry" use="@name"/>

 

<xsl:template match="bibref">

  <xsl:variable name="name" select="."/>

  <xsl:for-each select="document('bib.xml')">

    <xsl:apply-templates select="key('bib',$name)"/>

  </xsl:for-each>

</xsl:template>

 

12.3 数字格式

Function: string format-number (number , string , string ?)

函数 format-number 将参数number 中的数字按照第二个参数string 指定的格式转化成字符串,第三个参数用于指定小数格式(否则采用默认小数格式)。格式化字符串采用JDK1.1 DecimalFormat 类定义的语法,不能包含货币符号(#x00A4 )。小数格式必须是QName ,引用decimal-format 元素。

<!-- Category: top-level-element -->

<xsl:decimal-format

  name = qname

  decimal-separator = char

  grouping-separator = char

  infinity = string

  minus-sign = char

  NaN = string

  percent = char

  per-mille = char

  zero-digit = char

  digit = char

pattern-separator = char />

属性name 给出了小数格式的名称,如果没有指定name 属性则为默认小数格式。其他属性和JDK 1.1 DecimalFormatSymbols 类中的方法相对应。属性decimal-separator 指定小数部分的分隔符号,默认为“. ”(小数点)。属性percent 指定百分号,默认为%per-mille 千分位,默认为Unicode 千分符 (#x2030)zero-digit 指定代表零的符号,默认为0

下面两个属性控制格式化模式(字符串)的解释:digit 指定格式化字符串中的数字占位符,默认为#pattern-separator 用于将模式划分为两部分,分别用于正数和负数,默认值为;

下面三个属性指定可以出现在格式化结果中的字符或字符串:infinity 定义用于表示无限大的字符串,默认值为InfinityNaN 定义表示NaN 值的字符串,默认为NaNminus-sign 定义默认的负数符号,缺省值为-

 

12.4 杂项函数

Function: node-set current ()

返回一个节点集,其中只包含当前节点。对于最外层表达式,当前节点一定是上下文节点,因此<xsl:value-of select="current()"/><xsl:value-of select="."/> 是相同的。但是谓词中([] )中的当前节点通常和上下文节点不一致,比如<xsl:apply-templates select="//glossary/item[@name=current()/@ref]"/> 将处理glossaryname 属性与当前节点ref 属性相同的所有item 节点,而不同于<xsl:apply-templates select="//glossary/item[@name=./@ref]"/> ,后者相当于<xsl:apply-templates select="//glossary/item[@name=@ref]"/> ,即name 属性和ref 属性值相同的item 节点。模式中不能使用current 函数。

Function: string unparsed-entity-uri (string)

返回指定名称的非解析实体URI 作为当前节点。

Function: string generate-id (node-set?)

生成一个字符串唯一标识参数node-set 中的第一个节点,如果省略参数则默认为当前节点。生成的唯一标识符只能由ASCII 字母或数字组成,并且必须以字母开始。

Function: object system-property(string)

返回指定的系统属性。xsl:version ,处理器实现XSLT 版本号(数字); xsl:vendorXSLT 处理器提供商(字符串);xsl:vendor-url ,提供商的主页(字符串)。

 

13 消息

<!-- Category: instruction -->

<xsl:message  terminate = "yes" | "no">

  <!-- Content: template -->

</xsl:message>

发送一条消息,具体发送方式依赖于XSLT 处理器。Xsl:message 的内容是一个模板,实例化的时候创建一个XML 片段作为消息的内容。如果属性terminate 的值是yes ,发送这条消息后XSLT 处理器应停止处理,默认值为no

实现消息本地化,最好的办法是将某种语言的消息文本集中到一个文件中。比如,假设L 语言的消息存储到/L.xml 文件中:

<messages>

  <message name="problem">A problem was detected.</message>

  <message name="error">An error was detected.</message>

</messages>

样式表可通过下面的办法检索:

<xsl:param name="lang" select="en"/>

<xsl:variable name="messages"

  select="document(concat('resources/', $lang, '.xml'))/messages"/>

 

<xsl:template name="localized-message">

  <xsl:param name="name"/>

  <xsl:message>

    <xsl:value-of select="$messages/message[@name=$name]"/>

  </xsl:message>

</xsl:template>

 

<xsl:template name="problem">

  <xsl:call-template name="localized-message"/>

    <xsl:with-param name="name">problem</xsl:with-param>

  </xsl:call-template>

</xsl:template>

 

14 扩展

XSLT 支持两种形式的扩展:扩展元素和扩展函数。

 

15 退让

<!-- Category: instruction -->

<xsl:fallback>

  <!-- Content: template -->

</xsl:fallback>

通常实例化xsl:fallback 元素什么也不做。但是,如果XSLT 处理器对指令元素执行退让,而指令元素有一个或多个xsl:fallback 孩子,则所有xsl:fallback 孩子的内容必须按照顺序实例化。xsl:fallback 元素的内容是模板。

下列函数可与xsl:choosexsl:if 指令结合使用,定义如果某个元素或函数不存在样式表应如何处理。

Function: boolean element-available (string )

判定是否存在指定的指令。

Function: boolean function-available (string)

判定函数库中是否存在指定的函数。

 

16 Output

<!-- Category: top-level-element -->
<xsl:output
  method = "xml" | "html" | "text" | qname-but-not-ncname
  version = nmtoken
  encoding = string
  omit-xml-declaration = "yes" | "no"
  standalone = "yes" | "no"
  doctype-public = string
  doctype-system = string
  cdata-section-elements = qnames
  indent = "yes" | "no"
  media-type = string />

元素xsl:output 用于指定输出格式,只能作为顶层元素出现。属性method 定义了输出结果树的基本方式。如果没有前缀的话,只能是xmlhtmltext 之一。

如果结果树的根节点有元素孩子,而且第一个元素孩子(文档元素)的扩展名包含html (不论大小写)且没有名称空间URI ,第一个元素孩子之前的所有文本节点都只含空白字符,则默认输出方法为html ,否则默认输出方法为xml

Version 指定output 方法的版本;indent 说明输出结果树的时候是否允许添加空白,只能是yesnoencoding 指定对输出字符序列的编码方法,大小写敏感,必须是IANARFC2278 )注册的字符集或者以X- 开始;media-type 指定数据的MIME 媒体类型,不应包含charset 参数;doctype-system 指定文档类型声明中使用的系统标识符;doctype-public 指定文档类型声明使用的公共标识符;omit-xml-declaration 指定是否输出XML 声明,只能是yesnostandalone 指定是否输出独立文档声明,只能是yesnocdata-section-elements 指定一组元素名称,文本孩子结点使用CDATA 节输出。

16.1 XML 输出方法

Xml 输出方法将结果树作为良构的XML 一般可解析实体输出,如果结果树只有一个元素节点孩子而没有文本节点孩子,也可看做良构的XML 文档实体。 注意,输出XML 处理器可能需要增加名称空间声明。

Version 属性指定输出结果树使用的XML 版本,默认为1.0

Encoding 指定编码格式,处理器必须支持UTF-8UTF-16

属性indent 如果为yes ,可以使结果比较美观,默认值为no

16.2 HTML 输出方法

The html output method outputs the result tree as HTML; for example,

<xsl:stylesheet version="1.0"

                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="html"/>

<xsl:template match="/">

  <html>

   <xsl:apply-templates/>

  </html>

</xsl:template>

...

</xsl:stylesheet>

属性version 的默认值为4.0 。扩展名包含非空名称空间URI 的元素应该作为XML 输出。如果元素扩展名没有名称空间URI ,但是本地名也不是HTML 元素名,则作为非空的行内元素输出。空元素不输出结束标签,如areabasebasefontbrcolframehr, imginputisindexlinkmetaparam 。比如样式表中的<br/> <br></br> 应输出<br>HTML 元素名称不区分大小写,应该都能正确识别,如BRBr 应该都输出没有结束标签的brHtml 输出方法不能对脚本或样式元素的内容转义,比如<script>if (a &lt; b) foo()</script><script><![CDATA[if (a < b) foo()]]></script> 应该输出<script>if (a < b) foo()</script> 。不能转义属性值中出现的< 字符。Indent 的默认值是yesHtml 输出方法应该转义URI 属性值中出现的非ASCII 字符。输出处理指令时应用> 代替?> 。以最简形式输出布尔属性值,如<OPTION selected="selected"> 输出<OPTION selected> 。不能转义属性值中的“&{ ”,如<BODY bgcolor='&amp;{{randomrbg}};'> 应输出<BODY bgcolor='&{randomrbg};'>

如果有HEAD 元素,应添加META 元素指定实际使用的字符编码,如<HEAD><META http-equiv="Content-Type" content="text/html; charset=EUC-JP">...media-type 的默认值是text/html

 

16.3 Text 输出方法

文本输出方式不对字符进行转义, media-type 属性的默认值是text/plain

 

16.4 禁用输出转义

通常为保证输出XML 是良构的,xml 输出方法会对&< (可能还有其他字符)进行转义,但是对xsl:value-ofxsl:text 元素可通过disable-output-escaping =yes ’禁用输出转义。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值