Xml parsing - Xml PullParser parsing example analysis
XmlPullParser is an event-driven approach to parsing XML files. Because Android system has integrated this part, and the parsing part of XML file in Android framework is basically processed in this way, it is necessary for us to learn and understand the parsing process of XmlPull Parser and its usage so that we can read Android source code or use it in our work.
Xml Pull Parser is event-driven parsing process. The common events we use in our daily life are:
- XmlPullParser.START_DOCUMENT: The XML parser is currently at the beginning of the file and has not read any data yet.
- XmlPullParser.END_DOCUMENT: The end of a file in a logical sense; indicates that the current file stream processed by the XML parser has reached the end.
- XmlPullParser.START_TAG: The XML parser parses to a start tag
- XmlPullParser.END_TAG: The XML parser parses to an end tag
- XmlPullParser.TEXT: The XML parser parses the character data
There are also other events such as XmlPullParser.CDSECT and XmlPullParser.ENTITY_REF, which are not analyzed here because they are less involved.
After we read each event through the Xml PullParser parser, we can handle it according to the type of event. For example, when we encounter Xml PullParser. START_TAG, we can get the name of the current TAG, and then according to the meaning of our own TAG, we can carry out subsequent analysis and reading.
XmlPullParser sometimes involves the height of the currently parsed tag in the whole XML structure. We usually call getDepth() function to get the current TAG height. Let's take an example to see how Xml Pull Parser defines the height of TAG.
Example 1
The XML we want to parse is as follows:
<?xml version="1.0" encoding="utf-8"?> <root> <A> <B> <C> </C> <D /> </B> </A> <E> <F /> </E> <G /> </root>
Then use XmlPullParser to write an XML parsing code, and print to see how the height of each node is:
The results of code execution are as follows:public class XmlPullMain { public static void main(String[] args) { try { // InputStream xmlStream = new FileInputStream(new File("res/res.xml")); // XmlPullMain parserTool = new XmlPullMain(); // parserTool.parserXmlByPull(xmlStream, "UTF-8"); InputStream xmlStream = new FileInputStream(new File("res/test.xml")); XmlPullMain parserTool = new XmlPullMain(); parserTool.testDepth(xmlStream, "UTF-8"); } catch (FileNotFoundException e) { e.printStackTrace(); } } public void testDepth(InputStream xmlStream, String xmlEncode) { XmlPullParserFactory factory = null; XmlPullParser parser = null; try { factory = XmlPullParserFactory.newInstance(); factory.setNamespaceAware(true); parser = factory.newPullParser(); parser.setInput(xmlStream, xmlEncode); int event = parser.getEventType(); System.out.println("start current depth: " + parser.getDepth()); while (event != XmlPullParser.END_DOCUMENT) { switch (event) { case XmlPullParser.START_DOCUMENT: System.out.println("START_DOCUMENT depth: " + parser.getDepth()); break; case XmlPullParser.START_TAG: String node = parser.getName(); if (node.equals("root")) { System.out.println("root START_TAG depeth: " + parser.getDepth()); } else if (node.equals("A")) { System.out.println("A START_TAG depeth: " + parser.getDepth()); } else if (node.equals("B")) { System.out.println("B START_TAG depeth: " + parser.getDepth()); } else if (node.equals("C")) { System.out.println("C START_TAG depeth: " + parser.getDepth()); } else if (node.equals("D")) { System.out.println("D START_TAG depeth: " + parser.getDepth()); } else if (node.equals("E")) { System.out.println("E START_TAG depeth: " + parser.getDepth()); } else if (node.equals("F")) { System.out.println("F START_TAG depeth: " + parser.getDepth()); } else if (node.equals("G")) { System.out.println("G START_TAG depeth: " + parser.getDepth()); } break; case XmlPullParser.TEXT: System.out.println("--TEXT depth: " + parser.getDepth()); break; case XmlPullParser.END_TAG: String nodeEnd = parser.getName(); if (nodeEnd.equals("root")) { System.out.println("root END_TAG depeth: " + parser.getDepth()); } else if (nodeEnd.equals("A")) { System.out.println("A END_TAG depeth: " + parser.getDepth()); } else if (nodeEnd.equals("B")) { System.out.println("B END_TAG depeth: " + parser.getDepth()); } else if (nodeEnd.equals("C")) { System.out.println("C END_TAG depeth: " + parser.getDepth()); } else if (nodeEnd.equals("D")) { System.out.println("D END_TAG depeth: " + parser.getDepth()); } else if (nodeEnd.equals("E")) { System.out.println("E END_TAG depeth: " + parser.getDepth()); } else if (nodeEnd.equals("F")) { System.out.println("F END_TAG depeth: " + parser.getDepth()); } else if (nodeEnd.equals("G")) { System.out.println("G END_TAG depeth: " + parser.getDepth()); } break; case XmlPullParser.CDSECT: break; default: break; } event = parser.next(); } } catch (Exception e) { } } }
Based on the output, we can mark the height of each node in the Xml file:start current depth: 0 START_DOCUMENT depth: 0 root START_TAG depeth: 1 --TEXT depth: 1 A START_TAG depeth: 2 --TEXT depth: 2 B START_TAG depeth: 3 --TEXT depth: 3 C START_TAG depeth: 4 --TEXT depth: 4 C END_TAG depeth: 4 --TEXT depth: 3 D START_TAG depeth: 4 D END_TAG depeth: 4 --TEXT depth: 3 B END_TAG depeth: 3 --TEXT depth: 2 A END_TAG depeth: 2 --TEXT depth: 1 E START_TAG depeth: 2 --TEXT depth: 2 F START_TAG depeth: 3 F END_TAG depeth: 3 --TEXT depth: 2 E END_TAG depeth: 2 --TEXT depth: 1 G START_TAG depeth: 2 G END_TAG depeth: 2 --TEXT depth: 1 root END_TAG depeth: 1
<?xml version="1.0" encoding="utf-8"?> <!-- 0 --> <root><!-- 1 --> <A><!-- 2 --> <B><!-- 3 --> <C><!-- 4 --> </C><!-- 4 --> <D /><!-- 4 --> </B><!-- 3 --> </A><!-- 2 --> <E><!-- 2 --> <F /><!-- 3 --> </E><!-- 2 --> <G /><!-- 2 --> </root><!-- 1 -->
The integral value in the annotation tag is the height of the current node. From the results, we can see that the processing of the node height by Xml PullParser is based on the hierarchy of the node. If our XML file is written at a clear level, it is easy to see the height of each node in it.
In addition, from the output, we can see that:
- <a> In the form of </a> tags, two TEXT events are read during parsing: one after <a> START_TAG and one after </a> END_TAG.
- <b/> This form of tag only reads a TEXT event after <b> END_TAG, and no TEXT event occurs after <b> START_TAG.
This TEXT event sometimes doesn't make sense to us. For this reason, when we use Xml PullParser to parse Xml files, we have to deal with the events according to our own needs.
The basic usage of XmlPullParser is as shown in the example above:
- First, the InputStream stream corresponding to the XML file to be parsed is obtained.
- Instantiate the XmlPullParserFactory object
- Then get the parser instance of XmlPullParser type with the help of factory object
Then it can be parsed.
Xml Pull Parser has a fixed usage pattern, which is no longer explained here; other questions can be answered by looking at its source code.
Example 2
Here's an example that mimics the Android mainfest. XML configuration file parsing process.
The Xml file content we want to parse:
This is just a copy of the form in the Android configuration file. Look at the specific parsing code:<?xml version="1.0" encoding="utf-8"?> <!-- 0 --> <manifest package="com.example.androidtest" ><!-- 1 --> <uses-sdk minSdkVersion="19" targetSdkVersion="21">kitkat4.4</uses-sdk><!-- 2 --> <application allowBackup="true" icon="ic_launcher" ><!-- 2 --> <activity name="MainActivity" label="app_name" ><!-- 3 --> <intent-filter><!-- 4 --> <action name="android.intent.action.MAIN" /><!-- 5 --> <category name="android.intent.category.LAUNCHER" /><!-- 5 --> </intent-filter><!-- 4 --> </activity><!-- 3 --> <activity name="DefaultActivity" label="def_name" ><!-- 3 --> <intent-filter><!-- 4 --> <category name="android.intent.category.LAUNCHER" /><!-- 5 --> </intent-filter><!-- 4 --> <intent-filter><!-- 4 --> <category name="android.intent.category.HOME" /><!-- 5 --> </intent-filter><!-- 4 --> </activity><!-- 3 --> </application><!-- 2 --> <application allowBackup="false" icon="ic_launcher"><!-- 2 --> <activity name="TestActivity" label="test_name" ><!-- 3 --> <intent-filter><!-- 4 --> <category name="android.intent.category.LAUNCHER" /><!-- 5 --> </intent-filter><!-- 4 --> </activity><!-- 3 --> </application><!-- 2 --> </manifest><!-- 1 --> <!-- 0 -->
The output results are as follows:public class XmlPullMain { public static void main(String[] args) { try { InputStream xmlStream = new FileInputStream(new File("res/res.xml")); XmlPullMain parserTool = new XmlPullMain(); parserTool.parserXmlByPull(xmlStream, "UTF-8"); // InputStream xmlStream = new FileInputStream(new // File("res/test.xml")); // XmlPullMain parserTool = new XmlPullMain(); // parserTool.testDepth(xmlStream, "UTF-8"); } catch (FileNotFoundException e) { e.printStackTrace(); } } public void parserXmlByPull(InputStream xmlStream, String xmlEncode) { XmlPullParserFactory factory = null; XmlPullParser parser = null; try { factory = XmlPullParserFactory.newInstance(); factory.setNamespaceAware(true); parser = factory.newPullParser(); parser.setInput(xmlStream, xmlEncode); int event = parser.getEventType(); while (event != XmlPullParser.END_DOCUMENT) { switch (event) { case XmlPullParser.START_DOCUMENT: System.out.println("First we get START_DOCUMENT event"); break; case XmlPullParser.START_TAG: String node = parser.getName(); if (node.equals("manifest")) { System.out.println("now we parser manifest Tag"); System.out.println("\tmainfest attribute: " + parser.getAttributeValue(0)); } else if (node.equals("uses-sdk")) { System.out.println("now we parser uses-sdk Tag"); int count = parser.getAttributeCount(); for (int i = 0; i < count; i++) System.out.println("\tuses-sdk attribute: " + parser.getAttributeValue(i)); System.out.println("\tuses-sdk plateform: " + parser.nextText()); } else if (node.equals("application")) { System.out.println("now we parser Application Tag"); parserApplicationInfo(parser); } break; default: break; } event = parser.next(); } } catch (XmlPullParserException | IOException e) { e.printStackTrace(); } } private void parserApplicationInfo(XmlPullParser parser) throws XmlPullParserException, IOException { int count = parser.getAttributeCount(); for (int i = 0; i < count; i++) System.out.println("\twe parser Application attribute: " + parser.getAttributeValue(i)); int event = 0; int depth = parser.getDepth(); while ((event = parser.next()) != XmlPullParser.END_DOCUMENT && (parser.getDepth() > depth || event != XmlPullParser.END_TAG)) {//Parse only the contents of the current tag if (event == XmlPullParser.TEXT || event == XmlPullParser.END_TAG) { continue; } switch (event) { case XmlPullParser.START_TAG: String node = parser.getName(); if (node.equals("activity")) { parserActivityInfo(parser); } break; default: break; } } } private void parserActivityInfo(XmlPullParser parser) throws XmlPullParserException, IOException { int count = parser.getAttributeCount(); for (int i = 0; i < count; i++) System.out.println("\t\twe parser Activity -> attribute: " + parser.getAttributeValue(i)); int event = 0; int depth = parser.getDepth(); while ((event = parser.next()) != XmlPullParser.END_DOCUMENT && (parser.getDepth() > depth || event != XmlPullParser.END_TAG)) {//Parse only the contents of the current tag if (event == XmlPullParser.TEXT || event == XmlPullParser.END_TAG) { continue; } switch (event) { case XmlPullParser.START_TAG: String node = parser.getName(); if (node.equals("intent-filter")) { parserIntentInfo(parser); } break; default: break; } } } private void parserIntentInfo(XmlPullParser parser) throws XmlPullParserException, IOException { int event = 0; int depth = parser.getDepth(); while ((event = parser.next()) != XmlPullParser.END_DOCUMENT && (parser.getDepth() > depth || event != XmlPullParser.END_TAG)) {//Parse only the contents of the current tag if (event == XmlPullParser.TEXT || event == XmlPullParser.END_TAG) { continue; } switch (event) { case XmlPullParser.START_TAG: String node = parser.getName(); if (node.equals("action")) { System.out.println("\t\t\twe parser intent-filter action-> " + parser.getAttributeValue(0)); } else if (node.equals("category")) { System.out.println("\t\t\twe parser intent-filter category-> " + parser.getAttributeValue(0)); } break; default: break; } } } }
First we get START_DOCUMENT event now we parser manifest Tag mainfest attribute: com.example.androidtest now we parser uses-sdk Tag uses-sdk attribute: 19 uses-sdk attribute: 21 uses-sdk plateform: kitkat4.4 now we parser Application Tag we parser Application attribute: true we parser Application attribute: ic_launcher we parser Activity -> attribute: MainActivity we parser Activity -> attribute: app_name we parser intent-filter action-> android.intent.action.MAIN we parser intent-filter category-> android.intent.category.LAUNCHER we parser Activity -> attribute: DefaultActivity we parser Activity -> attribute: def_name we parser intent-filter category-> android.intent.category.LAUNCHER we parser intent-filter category-> android.intent.category.HOME now we parser Application Tag we parser Application attribute: false we parser Application attribute: ic_launcher we parser Activity -> attribute: TestActivity we parser Activity -> attribute: test_name we parser intent-filter category-> android.intent.category.LAUNCHER
The parsing of XML files in Android source code is basically based on this pattern. XmlPull Parser is also introduced here to enable us to better read Fucking Source Code.
End.