android 对xml文件的pull解析,生成xml ,对xml文件的增删

这篇博客介绍了XML的基本知识,包括start document和end document的概念,以及XML节点的结构和属性。重点讲解了Pull解析的工作原理,它是如何逐行扫描XML文件,将内容拆分为字符数组进行解析,并在节点开始和结束时触发相应事件,允许精确控制解析过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


xml知识补充:

在xml文件中,<?xml version= ....?> 称为 start document ,即xml起始位置,最末尾为 end document ,即为xml结束,每一个<>都是一个节点,称之为tag, <person>为starttag,而</person>为endtag         每个节点都可以有属性,<person id="1">,则id为attribute name,而1 为attribute value 节点也可以包含内容,    <name>Tom</name>, Tom就是内容,即text

pull解析:就是对xml文件的逐行扫描,pull解析器会将文件内容拆分为char[],逐字符读取,在调用其方法时,以每个节点为一次完整的读取来确定如恶化完成具体的解析工作

PULL一共有5种事件类型:
    * START_DOCUMENT:文档的开始,解析器尚未读取任何输入。
    * START_TAG:开始标签的解析。
    * TEXT:标签内元素的内容解析。
    * END_TAG:结束标签的解析。
    * END_DOCUMENT:文档的结束。

主要用的是4个,他们与XML文件相应内容是这么对应的(他们在XML文件中的位置是这样)
 
简单总结就是:
  1. 文档的开头和结束分别有文档开始和文档结束事件
  2. 文档中的每个节点,无论是根节点还是叶子节点,都在节点开始和节点结束的地方有事件
 
具体使用的建议:
  1. 文档开始和文档结束事件是有固定位置的,你只要在这个位置做你要做的事情就好了,比如初始化一些资源
  2. 节点开始和节点结束的事件在很多位置都可能发生,为了精确控制,你可以使用【获取他们的节点名称(name)进行判断】这一方法

代码:

data.xml,在assets目录下
<span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
<objects>
<students>
    <student id="2222" type="23">
        <name>王大</name>
        <sex>男</sex>
        <age>12</age>
        <grade>3</grade>
    </student>
</students>

<teachers>
    <teacher id="110" type="22">
        <name>张老师</name>
        <sex>男</sex>
        <age>12</age>
        <grade>3</grade>
    </teacher>
</teachers>

</objects></span>

这不是最常见的简单的xml,因为他里面包含了2个元素,students 和 teachers

一个简单的布局文件 activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    tools:context="${relativePackage}.${activityClass}" >

    <LinearLayout
        android:id="@+id/line_s"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:layout_alignParentTop="true"
        android:orientation="vertical" >

        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="6" >

            <TextView
                android:id="@+id/tv_result"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/hello_world" />
        </ScrollView>

        <EditText
            android:id="@+id/et_delete"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:background="#7f7f7f" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:gravity="bottom"
        android:orientation="vertical" >
        <Button
            android:id="@+id/btn_add_node_to_xml"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="add node to xml" />

        <Button
            android:id="@+id/btn_delete_from_xml"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="delete from xml" />

        <Button
            android:id="@+id/btn_in_db"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="writer to db" />

        <Button
            android:id="@+id/btn_writer_xml"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="writer to xml" />

        <Button
            android:id="@+id/btn_pull_analysis"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="analysis" />
    </LinearLayout>

</LinearLayout>

实体类
Teacher.class

@Column行可以无视删除,是因为这里用到这个倒数据库,Student.class 跟这个一样写就可以了

package com.example.pullanalysis;

import org.xutils.db.annotation.Column;

public class Teacher {
	@Column(name = "name")
	String name;
	@Column(name = "sex")
	String sex;
	@Column(name = "age")
	String age;
	@Column(name = "grade")
	String grade;
	@Column(name = "id")
	String id;
	@Column(name = "type")
	String type;
	@Column(name = "code")
	String code;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public String getAge() {
		return age;
	}
	public void setAge(String age) {
		this.age = age;
	}
	public String getGrade() {
		return grade;
	}
	public void setGrade(String grade) {
		this.grade = grade;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
	
	@Override
	public String toString() {
		return "Teacher [name=" + name 
				+ ", sex=" + sex 
				+ ", age=" + age 
				+ ", grade=" + grade 
				+ ", id=" + id 
				+ ", type="+ type 
				+ ", code=" + code 
				+ "]";
	}
	
}

MainActivity.class

<pre name="code" class="java">package com.example.pullanalysis;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import org.xutils.common.util.LogUtil;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.util.Xml;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener {

	/**
	 * 对xml文件的pull解析 生成xml文件 对xml文件的增加,删除
	 */

	private TextView mtvResult;
	private Button mbtnAnalysis;
	private Button mbtnWriter;
	private Button mbtnWriterdb;
	private Button mbtnDelete;
	private Button mbtnAdd;
	private EditText metdelete;
	private List<Student> mStudentlist;
	private List<Teacher> mTeacherlist;
	Map<String, Object> mListMap;

	private String path;
	private File file;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initView();
		initData();
	}

	private void initData() {
		// TODO Auto-generated method stub
		path = Environment.getExternalStorageDirectory().getAbsolutePath();

		file = new File(path, "Astudent.xml");

	}

	private void initView() {
		// TODO Auto-generated method stub
		mtvResult = (TextView) findViewById(R.id.tv_result);
		mbtnAnalysis = (Button) findViewById(R.id.btn_pull_analysis);
		mbtnWriter = (Button) findViewById(R.id.btn_writer_xml);
		mbtnWriterdb = (Button) findViewById(R.id.btn_in_db);
		mbtnDelete = (Button) findViewById(R.id.btn_delete_from_xml);
		metdelete = (EditText) findViewById(R.id.et_delete);
		mbtnAdd = (Button) findViewById(R.id.btn_add_node_to_xml);

		mListMap = new HashMap<String, Object>();

		mbtnAnalysis.setOnClickListener(this);
		mbtnWriter.setOnClickListener(this);
		mbtnWriterdb.setOnClickListener(this);
		mbtnDelete.setOnClickListener(this);
		mbtnAdd.setOnClickListener(this);
		metdelete.requestFocus();
		metdelete.setText("测试数据");
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
		case R.id.btn_pull_analysis:
			readxml();
			break;
		case R.id.btn_writer_xml:
			writertoxml(mListMap);
			break;
		case R.id.btn_in_db:
			writertodb();
			break;
		case R.id.btn_delete_from_xml:
			delete("teacher", "id", "0");
			break;
		case R.id.btn_add_node_to_xml:
			Map<String, String> map = new LinkedHashMap<String, String>();
			map.put("name", "白雪公主");
			map.put("sex", "man");
			map.put("age", "7");
			map.put("grade", "2");
			add("books", "book", "123", map);
			break;
		default:
			break;
		}
	}

	/**
	 * 将对象写入数据库
	 */
	private void writertodb() {
		TStudent tstu = new TStudent(MainActivity.this);
		Student stu = mStudentlist.get(0);
		boolean d = true;
		int n = 1;
		long btime = System.currentTimeMillis();
		long etime = 0;
		while (d) {
			tstu.insert(stu);
			if (n < 1000) {
				n++;
			} else {
				d = false;
				etime = System.currentTimeMillis();
				mtvResult.setText(String.valueOf(etime - btime));
			}
		}
	}

	/**
	 * pull 解析读取xml文件
	 */
	private void readxml() {
		try {

			InputStream ips = getAssets().open("data.xml");// 打开assets下的文件
			XmlPullParser parser = Xml.newPullParser();
			parser.setInput(ips, "utf-8");
			int eventtype = parser.getEventType();// 产生第一个事件
			Student student = null;
			Teacher teacher = null;
			StringBuffer str1 = new StringBuffer();
			StringBuffer str2 = new StringBuffer();
			while (eventtype != XmlPullParser.END_DOCUMENT) {
				switch (eventtype) {
				case XmlPullParser.START_DOCUMENT:// 判断当前事件是否为文档开始事件
					break;
				case XmlPullParser.START_TAG:// 判断当前事件是否为标签元素开始事件
					String name = parser.getName();
					if (name.equals("students")) {
						mStudentlist = new ArrayList<Student>();
					}
					if (name.equals("student")) { // 判断开始标签元素是否是student
						student = new Student();
						student.setCode("student");
						student.setId(parser.getAttributeValue(0));
						student.setType(parser.getAttributeValue(1));
					}
					if (student != null) {
						if (name.equals("name")) {
							student.setName(parser.nextText());
						} else if (name.equals("sex")) {
							student.setSex(parser.nextText());
						} else if (name.equals("age")) {
							student.setAge(parser.nextText());
						} else if (name.equals("grade")) {
							student.setGrade(parser.nextText());
						}
					}

					if (name.equals("teachers")) {
						mTeacherlist = new ArrayList<Teacher>();
					}

					if (name.equals("teacher")) {
						teacher = new Teacher();
						teacher.setCode("teacher");
						teacher.setId(parser.getAttributeValue(0));
						teacher.setType(parser.getAttributeValue(1));
					}

					if (teacher != null) {

						if (name.equals("name")) {
							teacher.setName(parser.nextText());
						} else if (name.equals("sex")) {
							teacher.setSex(parser.nextText());
						} else if (name.equals("age")) {
							teacher.setAge(parser.nextText());
						} else if (name.equals("grade")) {
							teacher.setGrade(parser.nextText());
						}

					}
					break;

				case XmlPullParser.END_TAG:// 判断当前事件是否为标签元素结束事件
					// 当读到student的时候,表示一个student对象读完了,这时候就可以把这个对象加入到list里了
					// 当然,在读到student前还会读到</name></sex>等的end_tag 直接无视就好了
					if (parser.getName().equals("student")) {
						mStudentlist.add(student);
						student = null;
					}
					if (parser.getName().equals("teacher")) {
						mTeacherlist.add(teacher);
						teacher = null;
					}
					// 读到</students>表示,students读完了
					if (parser.getName().equals("students")) {
						mListMap.put("students", mStudentlist);
					}

					if (parser.getName().equals("teachers")) {
						mListMap.put("teachers", mTeacherlist);
					}
					break;

				default:
					break;
				}
				eventtype = parser.next();// 不断的去更新,持续的解析XML文件直到文件的尾部。
			}

			if (mStudentlist != null && mStudentlist.size() != 0) {
				for (int i = 0; i < mStudentlist.size(); i++) {
					str1.append("name:" + mStudentlist.get(i).getName())
							.append("   sex:" + mStudentlist.get(i).getSex())
							.append("   age:" + mStudentlist.get(i).getAge())
							.append("   grade:" + mStudentlist.get(i).getGrade()).append("\n\n");
				}

				Toast.makeText(MainActivity.this, "解析成功", Toast.LENGTH_LONG).show();
			}
			if (mTeacherlist != null && mTeacherlist.size() != 0) {
				for (int i = 0; i < mTeacherlist.size(); i++) {
					str2.append("name:" + mTeacherlist.get(i).getName())
							.append("   sex:" + mTeacherlist.get(i).getSex())
							.append("   age:" + mTeacherlist.get(i).getAge())
							.append("   grade:" + mTeacherlist.get(i).getGrade()).append("\n\n");
				}
				Toast.makeText(MainActivity.this, "解析成功", Toast.LENGTH_SHORT).show();
			}
			mtvResult.setText(str1.toString() + "" + str2);
		} catch (IOException e) {
			LogUtil.d("IOException", e);
		} catch (XmlPullParserException e) {
			LogUtil.d("XmlPullParserException", e);
		}
	}

	/**
	 * 将对象的list写入xml文件
	 * 
	 * @param list
	 */
	private void writertoxml(Map<String, Object> listmap) {
		if (listmap != null && listmap.size() > 0) {
			FileOutputStream out = null;
			XmlSerializer xsl = Xml.newSerializer();

			List<Student> stlist = (List<Student>) listmap.get("students");

			List<Teacher> tealist = (List<Teacher>) listmap.get("teachers");
			int a = stlist.size();
			try {
				out = new FileOutputStream(file);
				xsl.setOutput(out, "utf-8");
				xsl.startDocument("utf-8", true);
				xsl.startTag("", "Object");
				xsl.attribute("", "path", "http://xxxx.yyyy.cc.v");
				xsl.attribute("", "time", "23:23:23");

				if (stlist != null && stlist.size() > 0) {
					xsl.startTag("", "students");
					int i = 0;
					for (Student stu : stlist) {
						String node = "student" + (i++);
						xsl.startTag("", "student");
						xsl.attribute("", "id", String.valueOf(i));
						xsl.attribute("", "type", stu.getType());

						xsl.startTag("", "name");
						xsl.text(stu.getName());
						xsl.endTag("", "name");

						xsl.startTag("", "sex");
						xsl.text(stu.getSex());
						xsl.endTag("", "sex");

						xsl.startTag("", "age");
						xsl.text(stu.getAge());
						xsl.endTag("", "age");

						xsl.startTag("", "grade");
						xsl.text(stu.getGrade());
						xsl.endTag("", "grade");

						xsl.endTag("", "student");
					}
					xsl.endTag("", "students");
				}

				if (tealist != null && tealist.size() > 0) {
					xsl.startTag("", "teachers");
					int j = 0;
					for (Teacher teacher : tealist) {
						String node = "teacher" + (j++);
						xsl.startTag("", "teacher");
						xsl.attribute("", "id", String.valueOf(j));
						xsl.attribute("", "type", teacher.getType());

						xsl.startTag("", "name");
						xsl.text(teacher.getName());
						xsl.endTag("", "name");

						xsl.startTag("", "sex");
						xsl.text(teacher.getSex());
						xsl.endTag("", "sex");

						xsl.startTag("", "age");
						xsl.text(teacher.getAge());
						xsl.endTag("", "age");

						xsl.startTag("", "grade");
						xsl.text(teacher.getGrade());
						xsl.endTag("", "grade");

						xsl.endTag("", "teacher");
					}
					xsl.endTag("", "teachers");
				}
				xsl.endTag("", "Object");
				xsl.endDocument();
				out.close();
				Toast.makeText(MainActivity.this, "写入成功", Toast.LENGTH_LONG).show();
			} catch (IllegalArgumentException e) {
				LogUtil.d("IllegalArgumentException", e);
			} catch (IllegalStateException e) {
				LogUtil.d("IllegalStateException", e);
			} catch (IOException e) {
				LogUtil.d("IOException", e);
			}
		}
	}

	/**
	 * 根据节点code以及对于的属性值删除对应的节点
	 * 
	 * @param code
	 * @param property
	 * @param value
	 */
	private void delete(String code, String property, String value) {// code,子节点,子节点的值
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder bulider = factory.newDocumentBuilder();
			Document doc = bulider.parse(file);
			doc.normalize();
			Element root = doc.getDocumentElement();// 得到根节点

			NodeList listnode = doc.getElementsByTagName(code);
			for (int i = 0; i < listnode.getLength(); i++) {
				Element elink = (Element) listnode.item(i);
				String prop = elink.getAttribute(property);
				if (prop.equals(value)) {
					if(listnode.getLength()==1){
						//如果只有一条数据,那么这条数据删除之后,大节点也应该被删除
						root.removeChild(elink.getParentNode());
					}else{
						elink.getParentNode().removeChild(elink);
					}
					Toast.makeText(MainActivity.this, "删除成功", Toast.LENGTH_LONG).show();

				}

			}
			TransformerFactory tfactory = TransformerFactory.newInstance();
			Transformer trans = tfactory.newTransformer();
			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(file);
			trans.transform(source, result);// 将原文件覆盖

		} catch (Exception e) {
			LogUtil.d("ParserConfigurationException", e);
		}
	}

	private int getMaxId(String code, String idnum) {
		int num = 0;
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder bulider = factory.newDocumentBuilder();
			Document doc = bulider.parse(file);
			doc.normalize();

			NodeList listnode = doc.getElementsByTagName(code);
			for (int i = 0; i < listnode.getLength(); i++) {
				Element elink = (Element) listnode.item(i);
				String id = elink.getAttribute(idnum);
				if (Integer.valueOf(id) > num) {
					num = Integer.valueOf(id);
				}
			}
			return num;
		} catch (ParserConfigurationException e) {
			LogUtil.d("ParserConfigurationException", e);
			return num;
		} catch (SAXException e) {
			LogUtil.d("SAXException", e);
			return num;
		} catch (IOException e) {
			LogUtil.d("IOException", e);
			return num;
		}
	}

	/**
	 * 添加节点尚不存在的对象
	 */

	private void addtoxml(String bigcode, String code, String type, Map<String, String> map) {
		FileOutputStream out = null;
		XmlSerializer xsl = Xml.newSerializer();
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder bulider = factory.newDocumentBuilder();// 1.通过DocumentBuilder工厂得到对应的xml解析器
			Document doc = bulider.parse(file);// 2.通过解析器得到Document对象
			doc.normalize();
			Element root = doc.getDocumentElement();// 得到根节点
			Element bigNode = doc.createElement(bigcode);
			Element codeNode = doc.createElement(code);
			codeNode.setAttributeNS("", "id", String.valueOf(getMaxId(code, "id") + 1));
			codeNode.setAttributeNS("", "type", type);

			for (String key : map.keySet()) {
				Node node = codeNode.appendChild(doc.createElement(key)).appendChild(doc.createTextNode(map.get(key)));
			}
			bigNode.appendChild(codeNode);
			root.appendChild(bigNode);

			TransformerFactory tfactory = TransformerFactory.newInstance();
			Transformer trans = tfactory.newTransformer();
			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(file);
			trans.transform(source, result);

			Toast.makeText(MainActivity.this, "增加成功", Toast.LENGTH_SHORT).show();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Log.d("www", e + "");
		}
	}

	/**
	 * 添加已存在节点的对象
	 * 
	 * @param code
	 */
	private void add(String bigCode, String code, String type, Map<String, String> map) {
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder bulider = factory.newDocumentBuilder();// 1.通过DocumentBuilder工厂得到对应的xml解析器
			Document doc = bulider.parse(file);// 2.通过解析器得到Document对象
			doc.normalize();
			Element root = doc.getDocumentElement();// 得到根节点
			NodeList employees = root.getChildNodes();

			// 判断是节点是否存在
			if (employees != null) {
				int flag = 0;
				for (int i = 0; i < employees.getLength(); i++) {
					Node mycode = employees.item(i);
					if (mycode.getNodeName().equals(bigCode)) {
						flag++;
					}
				}
				if (flag == 0) {
					addtoxml(bigCode, code, type, map);
					return;
				}

			}

			Element per = (Element) selectSingleNode("/Object/" + bigCode, root);
			Element codeNode = doc.createElement(code);
			codeNode.setAttributeNS("", "id", String.valueOf(getMaxId(code, "id") + 1));
			codeNode.setAttributeNS("", "type", type);
			for (String key : map.keySet()) {
				Node node = codeNode.appendChild(doc.createElement(key)).appendChild(doc.createTextNode(map.get(key)));
			}
			per.appendChild(codeNode);
			TransformerFactory tfactory = TransformerFactory.newInstance();
			Transformer trans = tfactory.newTransformer();
			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(file);
			trans.transform(source, result);
			Toast.makeText(MainActivity.this, "增加成功", Toast.LENGTH_LONG).show();
		} catch (ParserConfigurationException e) {
			LogUtil.d("ParserConfigurationException", e);
		} catch (SAXException e) {
			LogUtil.d("SAXException", e);
		} catch (IOException e) {
			LogUtil.d("IOException", e);
		} catch (TransformerConfigurationException e) {
			LogUtil.d("TransformerConfigurationException", e);
		} catch (TransformerException e) {
			LogUtil.d("TransformerException", e);
		}
	}

	/**
	 * 选择具体某一结点
	 * 
	 *
	 */
	public static Node selectSingleNode(String express, Element source) {
		Node result = null;
		XPathFactory xpathFactory = XPathFactory.newInstance();
		XPath xpath = xpathFactory.newXPath();
		try {
			result = (Node) xpath.evaluate(express, source, XPathConstants.NODE);
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		}
		return result;
	}
}




注:  1.运行的时候先点解析,在生成,增加,删除
2. 关于数据库的直接注释掉就可以了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值