一、引用
1、用XmlSerializer写xml文件与读xml文件
2、xml解析(读取xml,保存文件到xml)
3、Android-利用Document来对xml进行读取和写入操作
4、手把手教学 Android用jsoup解析html
文内相关其他XStream解析xml数据
1、Android XStream 解析xml数据变成bean,支持CDATA
2、Retrofit 用Soap协议访问WebService 详解
二、数据格式
1、xml数据
包含单个数据,列表数据,bean数据。有tag,attribute,content-text
以下我们就是我们要读取和写入的数据
*
*
*
*
*
* 仪器123
* 188
* YYY
* 检测兽药残留
*
*
* 仪器456
* 199
* XXX
* 检测农药残留及多参数
*
*
*
2、bean
public class DeviceInfo {
String name;
int id;
int price;
String company;
String usage;
public DeviceInfo(){}
public DeviceInfo(String name,int id,int price,String company,String usage){
this.name = name;
this.id = id;
this.price = price;
this.company = company;
this.usage = usage;
}
//省略get,set,tostring...
}
三、写入
1、XmlSerializer - xml序列,本质是pull
1.1、设置输出文件流FileOutputStream,xml序列号,文本格式...
1.2、startTag和endTag为一个元素的开始和结束标志
1.3、attribute 是当前tag的属性,一般来说bean的元素都可以放在里面
1.4、text 是tag的content-text,就是文本值
1.5、关闭xml序列文本、关闭FileOutputStream
/**写入XML数据*/
private void WriteXmlToSdcardByXmlSerial(){
List deviceInfoList = new ArrayList<>();
DeviceInfo deviceInfo = new DeviceInfo("仪器123",1,188,"YYY","检测兽药残留");
DeviceInfo deviceInfo3 = new DeviceInfo("仪器456",2,199,"XXX","检测农药残留及多参数");
deviceInfoList.add(deviceInfo);
deviceInfoList.add(deviceInfo3);
try {
//-------内部-----------
// // 指定流目录
// OutputStream os = openFileOutput("persons.xml", Context.MODE_PRIVATE);
// // 设置指定目录
// serializer.setOutput(os, "UTF-8");
//--------外部---------
//xml文件的序列号器 帮助生成一个xml文件
FileOutputStream fos = new FileOutputStream(new File(xmlPath));
//获取到xml的序列号
XmlSerializer serializer = Xml.newSerializer();
//序列化初始化
serializer.setOutput(fos, "utf-8");
//创建xml
serializer.startDocument("utf-8", true);
//顶层element有且只有一个
serializer.startTag(null,"xml_data");
//tag+attribute:
//tag+text:wujn
serializer.startTag(null,"user");
serializer.attribute(null,"name","wujn");
//serializer.text("wujn");
serializer.endTag(null,"user");
//多组...
serializer.startTag(null,"deviceinfos");
for(int i=0;i
2、Document - dom形式
1.1、DocumentBuilderFactory工厂新建一个document
1.2、createElement 新建元素,里面放的是tag值
1.3、setAttribute 设置attribute,一般bean类数据可放这里
1.4、setTextContent 是tag的content-text,就是文本值
1.5、appendChild 添加节点元素,一层层自己控制
1.6、Transformer 把document转成String
1.7、FileOutputStream 打开,写入String.getBytes(),关闭流
/**写入XML数据*/
private void WriteXmlToSdcardByDom(){
List deviceInfoList = new ArrayList<>();
DeviceInfo deviceInfo = new DeviceInfo("仪器123",1,188,"YYY","检测兽药残留");
DeviceInfo deviceInfo3 = new DeviceInfo("仪器456",2,199,"XXX","检测农药残留及多参数");
deviceInfoList.add(deviceInfo);
deviceInfoList.add(deviceInfo3);
try {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = null;
documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.newDocument();
document.setXmlStandalone(true);
document.setXmlVersion("1.0");
//根节点
Element root = document.createElement("xml_data");
//user节点
Element userE = document.createElement("user");
userE.setAttribute("name","wujn");
root.appendChild(userE);
//deviceinfos节点
Element devsE = document.createElement("deviceinfos");
for(int i=0;i
四、读取
1、XmlPullParser - Pull形式,一行行解析的,减少内存消耗
1、xml解析器设置解读编码和FileInputStream
2、getEventType 获得tag标签类型,按照不同类型进行解析
XmlResourceParser.END_DOCUMENT
XmlResourceParser.START_TAG
XmlResourceParser.TEXT - 标签内文本content-text
XmlResourceParser.END_TAG
3、next() 下一行,还有nextTag,nextText等
5、数据整合
6、关闭FileInputStream流
注意://如果xml节点确定是文本,需要检查XmlResourceParser.TEXT,防止getText() 返回 null。
/**
* XmlPullParser - 读取XML数据
* 逻辑上有可能有不严谨的地方
* */
private void ReadXmlFromSdcardByPull(){
File xmlFile = new File(xmlPath);
if(xmlFile.exists()){
try {
StringBuilder sb = new StringBuilder();
sb.append(" -- XmlPullParser --\n");
List deviceInfoList = new ArrayList<>();
DeviceInfo deviceInfo = null;
boolean convertDeviceInfo = false;
//文件写入流
FileInputStream fis = new FileInputStream(xmlFile);
//xml解析
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xrp = factory.newPullParser();
//设置input encode
xrp.setInput(fis, "UTF-8");
while (xrp.getEventType() != XmlResourceParser.END_DOCUMENT) {
if (xrp.getEventType() == XmlResourceParser.START_TAG) {
String tagName = xrp.getName();
if (tagName.equals("user")) {
String name = xrp.getAttributeValue(null, "name");
sb.append("user.name="+name+"\n");
}
else if(tagName.equals("deviceinfos")){
//nothing to do
}
else if(tagName.equals("deviceinfo")){
deviceInfo = new DeviceInfo();
int id = Integer.parseInt(xrp.getAttributeValue(null, "id"));
deviceInfo.setId(id);
LogUtil.d("id="+id);
convertDeviceInfo = true;
}
//解析 DeviceInfo
//text 是三个元素
if(convertDeviceInfo){
if(tagName.equals("name")) {
xrp.next();
//必须检查如果当前 xml 节点是文本,以便 getText() 不会返回 null。
if (xrp.getEventType() == XmlResourceParser.TEXT){
String name = xrp.getText();
deviceInfo.setName(name);
LogUtil.d("name="+name);
}
xrp.next();
}
else if(tagName.equals("price")){
xrp.next();
if (xrp.getEventType() == XmlResourceParser.TEXT){
int price = Integer.parseInt(xrp.getText());
deviceInfo.setPrice(price);
LogUtil.d("price="+price);
}
xrp.next();
}
else if(tagName.equals("company")){
xrp.next();
if (xrp.getEventType() == XmlResourceParser.TEXT){
String company = xrp.getText();
deviceInfo.setCompany(company);
LogUtil.d("company="+company);
}
xrp.next();
}
else if(tagName.equals("usage")){
xrp.next();
if (xrp.getEventType() == XmlResourceParser.TEXT){
String usage = xrp.getText();
deviceInfo.setUsage(usage);
LogUtil.d("usage="+usage);
}
xrp.next();
}
}
}
else if(xrp.getEventType() == XmlResourceParser.END_TAG){
String tagName = xrp.getName();
if(tagName.equals("deviceinfo")){
deviceInfoList.add(deviceInfo);
deviceInfo = null;
convertDeviceInfo = false;
}
}
//xrp.nextTag();
//xrp.nextText();
xrp.next();
}
//关闭流
fis.close();
fis=null;
for (int i=0;i
2、SAXParser - SAX形式
1、sax解析器设置FileInputStream 和解析助手handler
2、解析助手TestXmlHandler extends DefaultHandler
startDocument 开始文档
endDocument 结束文档
startElement 元素开始 :localName=tag标签名,attribute元素.getValue()获取元素值
endElement 元素结束
characters 元素内content-text
3、FileInputStream 刘关闭
注意:org.apache.harmony.xml.ExpatParser$ParseException: At line 1, column 76: junk after document element 这个异常是要么解析器解析写错了,要么就是xml文档不规范,比如顶层元素有多个,规定标准是只有一个顶层元素,在这里是xml_data
/**
* SAXParser - 读取XML数据
* 逻辑上有可能有不严谨的地方
*
* org.apache.harmony.xml.ExpatParser$ParseException: At line 1, column 76: junk after document element
* 顶层元素不止一个的异常
* */
private void ReadXmlFromSdcardBySAX(){
File xmlFile = new File(xmlPath);
if(xmlFile.exists()){
try {
final StringBuilder sb = new StringBuilder();
sb.append(" -- SAXParser --\n");
//文件写入流
FileInputStream fis = new FileInputStream(xmlFile);
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser saxParser = spf.newSAXParser();//创建解析器
//设置解析器的相关特性,http://xnl.org/sax/features/namespaces = true;
//表示开启命名空间特性
//saxParser.setProperty("http://xnl.org/sax/features/namespaces", true);
TestXmlHandler handler = new TestXmlHandler() {
@Override
void onStart() {
LogUtil.i("SAXParser onStart >>> ");
}
@Override
void onEnd(String username, List deviceInfoList) {
LogUtil.i("SAXParser onEnd >>> ");
sb.append("user.name="+username+"\n");
for (int i=0;i deviceInfoList = new ArrayList<>();
private DeviceInfo deviceInfo = null;
private boolean convertDeviceInfo = true;
private String preTag;//之前tag
@Override
public void startDocument() throws SAXException {
onStart();
}
@Override
public void endDocument() throws SAXException {
onEnd(username, deviceInfoList);
}
abstract void onStart();
abstract void onEnd(String username,List deviceInfoList);
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
LogUtil.d("startElement: uri="+uri+", localName="+localName+", qName="+qName);
preTag = localName;
if("user".equals(localName)){
username = attributes.getValue("name");
}
else if("deviceinfos".equals(localName)){
//will be more deviceinfo
}
else if("deviceinfo".equals(localName)){
deviceInfo = new DeviceInfo();
int id = Integer.parseInt(attributes.getValue("id"));
deviceInfo.setId(id);
convertDeviceInfo = true;
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
LogUtil.d("endElement: uri="+uri+", localName="+localName+", qName="+qName);
preTag = null;
if("deviceinfo".equals(localName)){
deviceInfoList.add(deviceInfo);
deviceInfo = null;
convertDeviceInfo = false;
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String data = new String(ch,start,length);
LogUtil.d("characters: preTag="+preTag+", data="+data);
if(convertDeviceInfo){
if(preTag.equals("name")) {
deviceInfo.setName(data);
LogUtil.d("name="+data);
}
else if(preTag.equals("price")){
int price = Integer.parseInt(data);
deviceInfo.setPrice(price);
LogUtil.d("price="+price);
}
else if(preTag.equals("company")){
deviceInfo.setCompany(data);
LogUtil.d("company="+data);
}
else if(preTag.equals("usage")){
deviceInfo.setUsage(data);
LogUtil.d("usage="+data);
}
}
}
}
3、Document - dom形式:此方式需要读取整个流数据,占用内存较大,一般针对小型xml数据可以用此方法,有点在于简单易懂
1、document加载输入流
2、getElementsByTagName 获得该tag名下的所有节点
3、每个node(Element)都有获取属性,属性name和值.getAttributes().getNamedItem("name").getNodeValue()
4、每个node(Element)的文本值 content-text : getTextContent();
5、关闭输入流
/**
* Document - 读取XML数据
* 直观明了,但是要预加载所有数据,对xml比较大占内存比较多
* */
private void ReadXmlFromSdcardByDom(){
File xmlFile = new File(xmlPath);
if(xmlFile.exists()){
try {
StringBuilder sb = new StringBuilder();
sb.append(" -- Document --\n");
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = null;
documentBuilder = documentBuilderFactory.newDocumentBuilder();
//加载输入流到document中
//InputStream inputStream = getAssets().open("person.xml");
FileInputStream fis = new FileInputStream(xmlFile);
Document document = documentBuilder.parse(fis);
NodeList userNodes = document.getElementsByTagName("user");
for(int i=0;i deviceInfoList = new ArrayList<>();
DeviceInfo deviceInfo = null;
NodeList deviceNodes = document.getElementsByTagName("deviceinfo");
//设备节点
for(int i=0;i
4、Jsoup- 和上面dom类似
1、Jsoup.parse 、Jsoup.connect 加载url或者htmlstring或者文件
2、getElementsByTag 获得该tag名下的所有节点,
3、children() 获得某节点元素下的所有元素
4、每个Element都有获取属性,attr(key)
5、每个Element的文本值 content-text : text();
compile 'org.jsoup:jsoup:1.9.2'
/**
* Jsoup - 读取XML数据(本质是document)
* 直观明了,但是要预加载所有数据,对xml比较大占内存比较多
* */
private void ReadXmlFromSdcardByJsoup(){
File xmlFile = new File(xmlPath);
if(xmlFile.exists()){
try {
StringBuilder sb = new StringBuilder();
sb.append(" -- Jsoup --\n");
//url网址作为输入源
//Document doc = Jsoup.connect("http://www.example.com").timeout(60000).get();
//File文件作为输入源
//File input = new File("/tmp/input.html");
//Document doc = Jsoup.parse(input, "UTF-8", "http://www.example.com/");
org.jsoup.nodes.Document document = Jsoup.parse(xmlFile, "UTF-8");
org.jsoup.select.Elements userE = document.getElementsByTag("user");
for(int i=0;i deviceInfoList = new ArrayList<>();
DeviceInfo deviceInfo = null;
org.jsoup.select.Elements deviceE = document.getElementsByTag("deviceinfo");
//设备节点
for(int i=0;i
五、读取和写入文本
/**
* 从file文件中读取string来
* */
public static String readFromFile(String fPath) throws IOException{
BufferedReader bf = new BufferedReader(new FileReader(fPath));
String content = "";
StringBuilder sb = new StringBuilder();
while (content != null) {
content = bf.readLine();
if (content == null) {
break;
}
sb.append(content.trim());
}
bf.close();
return sb.toString();
}
/**
* 写string到file文件中
* */
public static void writeToFile(String content,String fPath)throws IOException{
File txt = new File(fPath);
if (!txt.exists()) {
txt.createNewFile();
}
FileOutputStream fos = new FileOutputStream(txt);
fos.write(content.getBytes());
fos.flush();
fos.close();
}