Advanced Techniques

http://www.learn-xslt-tutorial.com/Advanced-XSLT-Techniques.cfm

Advanced Techniques

In this lesson of the XML tutorial, you will learn...
  1. To work with numbered lists.
  2. To output Processing Instructions.
  3. To create exact copies of matched nodes with  xsl:copy   and  xsl:copy-of .

Working with Numbered Lists

The position() function

The  position()   function returns the position of the context node in a selected set of nodes . The following XML and XSLT documents illustrate how  position()   works.

Code Sample: AdvancedXsltTechniques/Demos/BeatlesPosition.xml

<?xml version="1.0"?>
<?xml-stylesheet href="BeatlesPosition.xsl" type="text/xsl"?>
<beatles>
 <beatle link="http://www.paulmccartney.com">
  <name>
   <firstname>Paul</firstname>
   <lastname>McCartney</lastname>
  </name>
 </beatle>
 <beatle link="http://www.johnlennon.com">
  <name>
   <firstname>John</firstname>
   <lastname>Lennon</lastname>
  </name>
 </beatle>
 <beatle link="http://www.georgeharrison.com">
  <name>
   <firstname>George</firstname>
   <lastname>Harrison</lastname>
  </name>
 </beatle>
 <beatle link="http://www.ringostarr.com">
  <name>
   <firstname>Ringo</firstname>
   <lastname>Starr</lastname>
  </name>
 </beatle>
 <beatle link="http://www.webucator.com" real="no">
  <name>
   <firstname>Nat</firstname>
   <lastname>Dunn</lastname>
  </name>
 </beatle>
</beatles>

Code Sample: AdvancedXsltTechniques/Demos/BeatlesPosition.xsl

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/beatles">
 <xsl:apply-templates/>
</xsl:template>

<xsl:template match="beatle">
 <xsl:value-of select="position()"/>
 <xsl:text>. </xsl:text>
 <xsl:value-of select="name/lastname"/>

 <xsl:text>&#10;</xsl:text>
</xsl:template> 

</xsl:stylesheet>
Code Explanation

The result of transforming  AdvancedXsltTechniques/Demos/BeatlesPosition.xml   againstAdvancedXsltTechniques/Demos/BeatlesPosition.xsl   is shown below.

 1. McCartney
 2. Lennon
 3. Harrison
 4. Starr
 5. Dunn

Notice that the resulting list is numbered correctly. So far, so good. But look what happens when we add non-beatle   sibling to the  beatle   elements.

Code Sample: AdvancedXsltTechniques/Demos/BeatlesPosition-Oops.xml

<?xml version="1.0"?>
<?xml-stylesheet href="BeatlesPosition.xsl" type="text/xsl"?>
<beatles>
 <beatle link="http://www.paulmccartney.com">
  <name>
   <firstname>Paul</firstname>
   <lastname>McCartney</lastname>
  </name>
 </beatle>
 <beatle link="http://www.johnlennon.com">
  <name>
   <firstname>John</firstname>
   <lastname>Lennon</lastname>
  </name>
 </beatle>
 <oops />

 <beatle link="http://www.georgeharrison.com">
  <name>
   <firstname>George</firstname>
   <lastname>Harrison</lastname>
  </name>
 </beatle>
 <beatle link="http://www.ringostarr.com">
  <name>
   <firstname>Ringo</firstname>
   <lastname>Starr</lastname>
  </name>
 </beatle>
 <beatle link="http://www.webucator.com" real="no">
  <name>
   <firstname>Nat</firstname>
   <lastname>Dunn</lastname>
  </name>
 </beatle>
</beatles>
Code Explanation

As the result below shows, when we transform the file above against the same XSLT, the numbering is incorrect.

 1. McCartney
 2. Lennon
 4. Harrison
 5. Starr
 6. Dunn

This is because  position()   function returns the position of the current node within the selected node set and the  <Oops/>   element is in the selected node set, right between John Lennon and George Harrison.

This can be corrected by selecting a specific node-set with the  xsl:apply-templates   tag, but that can cause other problems.

xsl:number

The  <xsl:number /> tag provides another mechanism for numbering elements. It counts nodes that match a specified XPath. It works as follows.

First,  xsl:number   takes a  count   attribute, which takes an XPath indicating which  elements   to count. When not specified, the default of  count   is the name of the current element. When specified, the processor first looks at the current node and then looks up the tree at the current node's ancestors until it finds an element that matches the XPath specified in  count . It stops as soon as it finds a match.

Second,  xsl:number   takes a  level   attribute, which determines how many levels of the XML document should be examined for nodes that match the pattern specified in the  count   attribute. Possible values are  single ,  multiple and  any . We'll look at examples of each of these.

level = "single"

When  level="single"   (the default), a count is done of the node matched in the  count   attribute plus all preceding siblings that also match the XPath specified in  count .

Code Sample: AdvancedXsltTechniques/Demos/BeatlesNumbered.xsl

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/beatles">
 <xsl:apply-templates/>
</xsl:template>

<xsl:template match="beatle">
 <xsl:number level="single" count="beatle"/>

 <xsl:text>. </xsl:text>
 <xsl:value-of select="name/lastname"/>
 <xsl:text>&#10;</xsl:text>
</xsl:template> 

</xsl:stylesheet>
Code Explanation

Notice that  AdvancedXsltTechniques/Demos/BeatlesNumbered.xsl   has the  <oops/>   element between John Lennon and George Harrison; however, unlike with xsl:position, that element does not affect the output. This is because  xsl:number   is only  count ing the  beatle   elements. The result of transformingAdvancedXsltTechniques/Demos/BeatlesNumbered.xml   againstAdvancedXsltTechniques/Demos/BeatlesNumbered.xsl   is shown below.

 1. McCartney
 2. Lennon
 3. Harrison
 4. Starr
 5. Dunn

If  xsl:number   were changed to look like this:  <xsl:number level="single" count="*"/> , then<oops/>   would also be counted and the numbering would again be wrong.

level="any"

When  level="any" , a count is done of the node matched in the  count   attribute plus all preceding elements that also match the XPath specified in  count .

To illustrate how  any   works, we'll first take a look at another example using  level="single" .

Code Sample: AdvancedXsltTechniques/Demos/RockStars-Single.xml

<?xml version="1.0"?>
<?xml-stylesheet href="RockStars-Single.xsl" type="text/xsl"?>
<rockstars>
<beatles>
 <beatle link="http://www.paulmccartney.com">
  <name>
   <firstname>Paul</firstname>
   <lastname>McCartney</lastname>
  </name>
 </beatle>
 <beatle link="http://www.johnlennon.com">
  <name>
   <firstname>John</firstname>
   <lastname>Lennon</lastname>
  </name>
 </beatle>
</beatles>
<stones>
 <stone link="http://www.mickjagger.com" >
  <name>
   <firstname>Mick</firstname>
   <lastname>Jagger</lastname>
  </name>
 </stone>
 <stone link="http://www.keithrichards.com" >
  <name>
   <firstname>Keith</firstname>
   <lastname>Richards</lastname>
  </name>
 </stone>
</stones>
</rockstars>

Code Sample: AdvancedXsltTechniques/Demos/RockStars-Single.xsl

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/beatles">
 <xsl:apply-templates/>
</xsl:template>

<xsl:template match="beatle | stone">
 <xsl:number level="single" count="beatle | stone"/>

 <xsl:text>. </xsl:text>
 <xsl:value-of select="name/lastname"/>
 <xsl:text>&#10;</xsl:text>
</xsl:template> 

</xsl:stylesheet>
Code Explanation

The result of transforming  AdvancedXsltTechniques/Demos/RockStars-Single.xml   againstAdvancedXsltTechniques/Demos/RockStars-Single.xsl   is shown below.

 1. McCartney
 2. Lennon
 1. Jagger
 2. Richards

Notice that the counting is done at a single level. In other words, only siblings are counted.

Now let's see what happens when  level="single"   is changed to  level="any"   as shown inAdvancedXsltTechniques/Demos/RockStars-Any.xsl .

Code Sample: AdvancedXsltTechniques/Demos/RockStars-Any.xsl

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/beatles">
 <xsl:apply-templates/>
</xsl:template>

<xsl:template match="beatle | stone">
 <xsl:number level="any" count="beatle | stone"/>

 <xsl:text>. </xsl:text>
 <xsl:value-of select="name/lastname"/>
 <xsl:text>&#10;</xsl:text>
</xsl:template> 

</xsl:stylesheet>
Code Explanation

The result of transforming  AdvancedXsltTechniques/Demos/RockStars-Any.xml   againstAdvancedXsltTechniques/Demos/RockStars-Any.xsl   is shown below.

 1. McCartney
 2. Lennon
 3. Jagger
 4. Richards

As you can see, the counting is now done across levels.

level="multiple"

When  level="multiple" , multiple counts are done at different levels.  To determine the results, the processor goes through the following steps.

  1. It creates a list of all the ancestors of the current node and the current node itself.
  2. It throws out any nodes in the list that do not match the XPath specified in the  count   attribute.
  3. It maps each node in the list to a number, which is calculated by counting the node's preceding siblings that match the XPath specified in the  count   attribute and adding one (for the node itself).

Code Sample: AdvancedXsltTechniques/Demos/Outline.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="Outline.xsl"?>
<outline>
 <topic>XML Basics<topic>What is XML?</topic>
  <topic>XML Benefits<topic>XML Holds Data, Nothing More</topic>
   <topic>XML Separates Structure from Formatting</topic>
   <topic>XML Promotes Data Sharing</topic>
   <topic>XML is Human-Readable</topic>
   <topic>XML is Free</topic>
  </topic>
  <topic>XML Documents<topic>The Prolog</topic>
   <topic>Elements</topic>
   <topic>Attributes</topic>
   <topic>CDATA</topic>
   <topic>XML Syntax Rules</topic>
   <topic>Special Characters</topic>
  </topic>
  <topic>Creating a Simple XML File</topic>
 </topic>
</outline>

Code Sample: AdvancedXsltTechniques/Demos/Outline.xsl

<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:template match="/">
 <xsl:apply-templates select="outline//*"/>
</xsl:template>

<xsl:template match="outline//*">
 <xsl:for-each select="ancestor::*">
  <xsl:text>&#09;</xsl:text>
 </xsl:for-each>
 <xsl:number level="multiple" count="*"/>

 <xsl:text>. </xsl:text>
 <xsl:value-of select="text()"/>
 <xsl:text>&#10;</xsl:text>
</xsl:template>

</xsl:stylesheet>
Code Explanation

The result of transforming  AdvancedXsltTechniques/Demos/Outline.xml   againstAdvancedXsltTechniques/Demos/Outline.xml   is shown below.

 1.1. XML Basics
  1.1.1. What is XML?
  1.1.2. XML Benefits
   1.1.2.1. XML Holds Data, Nothing More
   1.1.2.2. XML Separates Structure from Formatting
   1.1.2.3. XML Promotes Data Sharing
   1.1.2.4. XML is Human-Readable
   1.1.2.5. XML is Free
  1.1.3. XML Documents
   1.1.3.1. The Prolog
   1.1.3.2. Elements
   1.1.3.3. Attributes
   1.1.3.4. CDATA
   1.1.3.5. XML Syntax Rules
   1.1.3.6. Special Characters
  1.1.4. Creating a Simple XML File

The tabbing is generated with the  <xsl:for-each> , which renders one tab for each ancestor of the current element. As the processor looks deeper into the document, the elements have more ancestors and, therefore, are preceded by more tabs.

The first number "1" of each line in the output above represents the  Outline   element, which is the document element. Because a well-formed XML document can only have one document element, every list generated withxsl:number   in this way will start every list item with the number "1". This can be fixed with the  from   attribute.

The from Attribute

The  from   attribute takes a regular expression specifying where counting should start.

Code Sample: AdvancedXsltTechniques/Demos/OutlineFrom.xsl

<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:template match="/">
 <xsl:apply-templates select="outline//*"/>
</xsl:template>

<xsl:template match="outline//*">
 <xsl:for-each select="ancestor::*">
  <xsl:text>&#09;</xsl:text>
 </xsl:for-each>
 <xsl:number level="multiple" count="*" from="outline"/>

 <xsl:text>. </xsl:text>
 <xsl:value-of select="text()"/>
 <xsl:text>&#10;</xsl:text>
</xsl:template>

</xsl:stylesheet>
Code Explanation

The result of transforming  AdvancedXsltTechniques/Demos/OutlineFrom.xml   againstAdvancedXsltTechniques/Demos/OutlineFrom.xsl   is shown below.

 1. XML Basics
  1.1. What is XML?
  1.2. XML Benefits
   1.2.1. XML Holds Data, Nothing More
   1.2.2. XML Separates Structure from Formatting
   1.2.3. XML Promotes Data Sharing
   1.2.4. XML is Human-Readable
   1.2.5. XML is Free
  1.3. XML Documents
   1.3.1. The Prolog
   1.3.2. Elements
   1.3.3. Attributes
   1.3.4. CDATA
   1.3.5. XML Syntax Rules
   1.3.6. Special Characters
  1.4. Creating a Simple XML File

Notice that the initial "1" is now stripped. That's because the processor is now counting from the  Outline element rather than from the root node.

Formatting Numbers

In the last example, you may have noticed that the levels are all represented with Arabic numbers. The formatting can be changed with the  format   attribute, which takes a format token, which is a delimited list of characters. The same delimiter used in the format token is used in the output.

Code Sample: AdvancedXsltTechniques/Demos/OutlineFormatted.xsl

<?xml version='1.0'?>
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:template match="/">
 <xsl:apply-templates select="outline//*"/>
</xsl:template>

<xsl:template match="outline//*">
 <xsl:for-each select="ancestor::*">
  <xsl:text>&#09;</xsl:text>
 </xsl:for-each>
 <xsl:number level="multiple" count="*" format="I.A.i.a. "/>

 <xsl:value-of select="text()"/>
 <xsl:text>&#10;</xsl:text>
</xsl:template>

</xsl:stylesheet>

In earlier examples, we placed a period and a space after the number by putting  <xsl:text>. </xsl:text>   afterxsl:number . In this example, we accomplished the same thing by placing a period and a space at the end of the format token.

Outputting Processing Instructions

It is sometimes necessary to output processing instructions with XSLT; for example, if you need to transform one XML document to another XML structure, which will then be transformed to HTML via XSLT. This is illustrated in the diagram below.

Processing instructions are output with the  xsl:processing-instruction   element as shown below.

Syntax
<xsl:processing-instruction name="Name_Of_Instruction">
   Name-Value Pairs of Instruction
</xsl:processing-instruction>

Let's look at an example.

Code Sample: AdvancedXsltTechniques/Demos/Beatles.xml

<?xml version="1.0"?>
<?xml-stylesheet href="Beatles2Artists.xsl" type="text/xsl"?>
<beatles>
 <beatle link="http://www.paulmccartney.com">
  <name>
   <firstname>Paul</firstname>
   <lastname>McCartney</lastname>
  </name>
 </beatle>
 <beatle link="http://www.johnlennon.com">
  <name>
   <firstname>John</firstname>
   <lastname>Lennon</lastname>
  </name>
 </beatle>
 <beatle link="http://www.georgeharrison.com">
  <name>
   <firstname>George</firstname>
   <lastname>Harrison</lastname>
  </name>
 </beatle>
 <beatle link="http://www.ringostarr.com">
  <name>
   <firstname>Ringo</firstname>
   <lastname>Starr</lastname>
  </name>
 </beatle>
 <beatle link="http://www.webucator.com" real="no">
  <name>
   <firstname>Nat</firstname>
   <lastname>Dunn</lastname>
  </name>
 </beatle>
</beatles>

Code Sample: AdvancedXsltTechniques/Demos/Beatles2Artists.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" indent="yes"/>
 <xsl:template match="/beatles">
  <xsl:text>&#10;</xsl:text>
  <xsl:processing-instruction name="xml-stylesheet">
   <xsl:text>href="Artists.xsl" type="text/xsl"</xsl:text>
  </xsl:processing-instruction>

  <xsl:text>&#10;</xsl:text>
  <Artists>
   <xsl:apply-templates/>
  </Artists>
 </xsl:template>
 <xsl:template match="beatle">
  <Artist>
   <FirstName>
    <xsl:value-of select="name/firstname"/>
   </FirstName>
   <LastName>
    <xsl:value-of select="name/lastname"/>
   </LastName>
  </Artist>
 </xsl:template>
</xsl:stylesheet>
Code Explanation

The result of transforming  AdvancedXsltTechniques/Demos/Beatles.xml   againstAdvancedXsltTechniques/Demos/Beatles2Artists.xsl   is shown below.

Code Sample: AdvancedXsltTechniques/Demos/BeatlesOutput.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="Artists.xsl" type="text/xsl"?>

<Artists>
 <Artist>
  <FirstName>Paul</FirstName>
  <LastName>McCartney</LastName>
 </Artist>
 <Artist>
  <FirstName>John</FirstName>
  <LastName>Lennon</LastName>
 </Artist>
 <Artist>
  <FirstName>George</FirstName>
  <LastName>Harrison</LastName>
 </Artist>
 <Artist>
  <FirstName>Ringo</FirstName>
  <LastName>Starr</LastName>
 </Artist>
 <Artist>
  <FirstName>Nat</FirstName>
  <LastName>Dunn</LastName>
 </Artist>
</Artists>
Code Explanation

As you can see from the output above, the generated XML document has a processing instruction which indicates that it should be transformed against  Artists.xsl   (shown below).

Code Sample: AdvancedXsltTechniques/Demos/Artists.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" indent="yes"/>
 <xsl:template match="/">
  <html>
   <head>
    <title>Artists</title>
   </head>
   <body>
    <h1>Artists</h1>
    <table>
      <tr>
       <th>First Name</th>
       <th>Last Name</th>
      </tr>
      <xsl:apply-templates/>
    </table>
   </body>
  </html>
 </xsl:template>
 <xsl:template match="Artist">
  <tr>
   <td><xsl:value-of select="FirstName"/></td>
   <td><xsl:value-of select="LastName"/></td>
  </tr>
 </xsl:template>
</xsl:stylesheet>
Code Explanation

The result of transforming  AdvancedXsltTechniques/Demos/BeatlesOutput.xml   againstAdvancedXsltTechniques/Demos/Artists.xsl   is shown below.

Code Sample: AdvancedXsltTechniques/Demos/Beatles.html

<?xml version="1.0" encoding="UTF-8"?>
<html>
 <head>
  <title>Artists</title>
 </head>
 <body>
  <h1>Artists</h1>
  <table>
   <tr>
    <th>First Name</th>
    <th>Last Name</th>
   </tr>
   <tr>
    <td>Paul</td>
    <td>McCartney</td>
   </tr>
   <tr>
    <td>John</td>
    <td>Lennon</td>
   </tr>
   <tr>
    <td>George</td>
    <td>Harrison</td>
   </tr>
   <tr>
    <td>Ringo</td>
    <td>Starr</td>
   </tr>
   <tr>
    <td>Nat</td>
    <td>Dunn</td>
   </tr>
  </table>
 </body>
</html>

Copying Nodes

Sometimes you find that there is a chunk of code from the source XML document that you want to leave exactly as is in the output. There are two tags that make this very easy to do in XSLT:  xsl:copy   and  xsl:copy-of .

xsl:copy

The  xsl:copy   element is used to copy the element name from the source document. The following example illustrates how it is used.

Code Sample: AdvancedXsltTechniques/Demos/BeatlesCopy.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" indent="yes"/>
 <xsl:template match="/beatles">
  <xsl:copy>

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

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

   <xsl:value-of select="lastname"/>, <xsl:value-of select="firstname"/>
  </xsl:copy>

 </xsl:template>
</xsl:stylesheet>
Code Explanation

The first  xsl:copy   outputs a beatles node and the second  xsl:copy   outputs a name node for each name node in the source document. When  AdvancedXsltTechniques/Demos/BeatlesCopy.xml   is transformed againstAdvancedXsltTechniques/Demos/BeatlesCopy.xsl , the output looks like this.

Code Sample: AdvancedXsltTechniques/Demos/BeatlesCopyOutput.xml

<?xml version="1.0" encoding="UTF-8"?>
<beatles>
 <name>McCartney, Paul</name>
 <name>Lennon, John</name>
 <name>Harrison, George</name>
 <name>Starr, Ringo</name>
 <name>Dunn, Nat</name>
</beatles>

xsl:copy-of

The  xsl:copy-of   element is used to make a deep copy from the source document, including all attributes and descendant elements. The following example illustrates how it is used.

Code Sample: AdvancedXsltTechniques/Demos/BeatlesCopyOf.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" indent="yes"/>
 <xsl:template match="/beatles">
  <xsl:copy>
   <xsl:apply-templates select="//name"/>
  </xsl:copy>
 </xsl:template>
 <xsl:template match="name">
  <xsl:copy-of select="."/>

 </xsl:template>
</xsl:stylesheet>
Code Explanation

The  xsl:copy-of   outputs a deep copy of a name node for each name node in the source document. WhenAdvancedXsltTechniques/Demos/BeatlesCopyOf.xml   is transformed againstAdvancedXsltTechniques/Demos/BeatlesCopyOf.xsl , the output looks like this.

Code Sample: AdvancedXsltTechniques/Demos/BeatleCopyOfOutput.xml

<?xml version="1.0" encoding="UTF-8"?>
<beatles>
 <name>
  <firstname>Paul</firstname>
  <lastname>McCartney</lastname>
 </name>
 <name>
  <firstname>John</firstname>
  <lastname>Lennon</lastname>
 </name>
 <name>
  <firstname>George</firstname>
  <lastname>Harrison</lastname>
 </name>
 <name>
  <firstname>Ringo</firstname>
  <lastname>Starr</lastname>
 </name>
 <name>
  <firstname>Nat</firstname>
  <lastname>Dunn</lastname>
 </name>
</beatles>

Advanced Techniques Conclusion

In this lesson of the XML tutorial, you have learned how to work with numbered lists, output processing instructions, and create copies of elements from the source document to the output.

To continue to learn XML go to the   top of this page   and click on the next lesson in this XML Tutorial's Table of Contents.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值