xml解析方式一般分为三种解析方式,下面通过一段xml,使用三种方式解析,首先来看下要解析的xml:
<simple>
<paragraph>
<text content="北京市,简称“" />
<text content="京" link="https://baike.baidu.com/item/京/15808773" />
<text content="”,是中华人民共和国省级行政区、" />
<text content="首都" link="https://baike.baidu.com/item/首都/26194" />
<text content="、" />
<text content="直辖市" link="https://baike.baidu.com/item/直辖市/725471" />
<text content="国家中心城市" link="https://baike.baidu.com/item/国家中心城市/842500" />
<text content="、超大城市,全国" />
<text content="政治中心" link="https://baike.baidu.com/item/政治中心/3218495" />
<text content="、文化中心、国际交往中心、科技创新中心,是世界著名古都和现代化国际城市,是" />
<text content="中国共产党中央委员会" link="https://baike.baidu.com/item/中国共产党中央委员会/1141242" />
<text content="、" />
<text content="中华人民共和国中央人民政府" link="https://baike.baidu.com/item/中华人民共和国中央人民政府/5693897" />
<text content="和全国人民代表大会常务委员会的办公所在地。" />
</paragraph>
<paragraph>
<text content="北京地处中国华北地区,中心位于东经" />
<text strong="116°20′" />
<text content="北纬" />
<text strong="39°56′" />
<text content="东与" />
<text content="天津" link="https://baike.baidu.com/item/天津/132308" />
<text content="毗连,其余均与" />
<text content="河北" link="https://baike.baidu.com/item/河北/65777" />
<text content="相邻,北京市总面积" />
<text strong="16410.54" />
<text content="平方千米。截至" />
<text strong="2017" />
<text content="年底,北京市下辖" />
<text strong="16" />
<text content="个市辖区。" />
</paragraph>
</simple>
这是两个段落的语句,最终解析完成后,需要通过textview的span显示在textview上面:
image.png
标签分别有content、strong、link等内容,为了实现三种xml解析方式,这里写了个简单的工厂模式:
image.png
分别对应了pull、dom、sax解析方式。
- pull解析,pull解析是拿到每一个标签,是并行解析,然后每拿到一个解析的标签触发到
XmlPullParser.START_TAG
,解析完了该标签后触发XmlPullParser.END_TAG
,通过XmlPullParser.getEventType
可以拿到是标签的开始,还是结束,还是整个xml的结束,XmlPullParser.next
可以知道是不是xml结束,XmlPullParser.getDepth
可以知道当前标签是嵌套了几层,一般被称为标签深度。其中pull解析现在用得多的org.xmlpull.v1.XmlPullParserFactory
来创建XmlPullParser
,还有种方式是通过Xml.newPullParser
来创建。
public class PullParse implements Parse {
@Override
public List<Paragraph> parse(InputStream is) throws Exception {
List<Paragraph> paragraphs = null;
Paragraph paragraph =p null;
Text tag = null;
//创建xmlPull解析器
//org.xmlpull.v1解析方式
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
//区分namespace
factory.setNamespaceAware(true);
XmlPullParser parser = factory.newPullParser();
//传统的xml解析方式
XmlPullParser parser1 = Xml.newPullParser();
///初始化xmlPull解析器
parser.setInput(is, "utf-8");
//读取文件的类型
int type = parser.getEventType();
//对应当前节点的深度
int startDepth = parser.getDepth();
Log.d("PullParse", "startDepth:" + startDepth);
//无限判断文件类型进行读取
//pull解析是按照节点的start_tag和end_tag来解析,在遍历的时候通过判断是不是到了节点的结尾
while (type != XmlPullParser.END_DOCUMENT) {
switch (type) {
//开始标签
case XmlPullParser.START_TAG:
if ("simple".equals(parser.getName())) {
paragraphs = new ArrayList<>();
int simpleDepth = parser.getDepth();
Log.d("PullParse", "simpleDepth:" + simpleDepth);
} else if ("paragraph".equals(parser.getName())) {
paragraph = new Paragraph();
int paragraphDepth = parser.getDepth();
Log.d("PullParse", "paragraphDepth:" + paragraphDepth);
} else if ("text".equals(parser.getName())) {
tag = new Text();
int textDepth = parser.getDepth();
Log.d("PullParse", "textDepth:" + textDepth);
String link = parser.getAttributeValue(null, "link");
String content = parser.getAttributeValue(null, "content");
String strong = parser.getAttributeValue(null, "strong");
tag.link = link;
tag.content = content;
tag.strong = strong;
}
break;
//结束标签
case XmlPullParser.END_TAG:
if ("text".equals(parser.getName())) {
paragraph.tags.add(tag);
} else if ("paragraph".equals(parser.getName())) {
paragraphs.add(paragraph);
}
break;
}
//继续往下读取标签类型
type = parser.next();
}
return paragraphs;
}
}
image.png
- dom解析,该种解析首先拿到整个xml的直接子节点,例子中的子节点是
paragraph
,然后里面可以通过Node.getChildNodes
方式获取到NodeList
,
Node.getNamedItem
可以获取到标签里面的内容:
public class DomParse implements Parse {
@Override
public List<Paragraph> parse(InputStream is) throws Exception {
List<Paragraph> list = new ArrayList<>();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(is);
//dom解析首先是获取到当前有几个直接的子节点
NodeList studentList = document.getElementsByTagName("paragraph");
for (int i = 0; i < studentList.getLength(); i++) {
Node node_student = studentList.item(i);
NodeList childNodes = node_student.getChildNodes();
Paragraph student = new Paragraph();
for (int j = 0; j < childNodes.getLength(); j++) {
Node childNode = childNodes.item(j);
if ("text".equals(childNode.getNodeName())) {
Text text = new Text();
NamedNodeMap nnm = childNode.getAttributes();
Node linkNode = nnm.getNamedItem("link");
Node contentNode = nnm.getNamedItem("content");
Node strongNode = nnm.getNamedItem("strong");
if (linkNode != null && !TextUtils.isEmpty(linkNode.getTextContent())) {
text.link = linkNode.getTextContent();
}
if (contentNode != null && !TextUtils.isEmpty(contentNode.getTextContent())) {
text.content = contentNode.getTextContent();
}
if (strongNode != null && !TextUtils.isEmpty(strongNode.getTextContent())) {
text.strong = strongNode.getTextContent();
}
student.tags.add(text);
}
}
//加到List中
list.add(student);
}
return list;
}
}
- sax解析有点像pull解析,也是并行解析的,解析的时候会触发到
startElement
,endElement
等方法。
public class SaxParse implements Parse {
@Override
public List<Paragraph> parse(InputStream is) throws Exception {
SAXParserFactory spf = SAXParserFactory.newInstance();
//初始化Sax解析器
SAXParser sp = spf.newSAXParser();
//新建解析处理器
MyHandler handler = new MyHandler();
//将解析交给处理器
sp.parse(is, handler);
//返回List
return handler.getList();
}
public static class MyHandler extends DefaultHandler {
private List<Paragraph> list;
private Paragraph paragraph;
Text text;
/**
* 解析到文档开始调用,一般做初始化操作
*
* @throws SAXException
*/
@Override
public void startDocument() throws SAXException {
list = new ArrayList<>();
super.startDocument();
}
/**
* 解析到文档末尾调用,一般做回收操作
*
* @throws SAXException
*/
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
/**
* 每读到一个元素就调用该方法
*
* @param uri
* @param localName
* @param qName
* @param attributes
* @throws SAXException
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if ("text".equals(qName)) {
//读到student标签
text = new Text();
text.link = attributes.getValue("link");
text.strong = attributes.getValue("strong");
text.content = attributes.getValue("content");
} else if ("paragraph".equals(qName)) {
paragraph = new Paragraph();
}
super.startElement(uri, localName, qName, attributes);
}
/**
* 读到元素的结尾调用
*
* @param uri
* @param localName
* @param qName
* @throws SAXException
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if ("text".equals(qName)) {
paragraph.tags.add(text);
} else if ("paragraph".equals(qName)) {
list.add(paragraph);
}
super.endElement(uri, localName, qName);
}
/**
* 读到属性内容调用
*
* @param ch
* @param start
* @param length
* @throws SAXException
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
}
/**
* 获取该List
*
* @return
*/
public List<Paragraph> getList() {
return list;
}
}
}
好了,几种解析方式就介绍到这里,在解析之后,还需要掌握textview各种span的设置。常用的有ForegroundColorSpan:设置部分文字颜色的span
,ClickableSpan:部分文字点击的span
,StyleSpan:可以设置粗体的span,关于stylespan其他的样式大家可以尝试
。
完整demo点这里
网友评论