Xml parsing - Xml PullParser parsing example analysis

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:

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) {

		}
	}

}
The results of code execution are as follows:
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
Based on the output, we can mark the height of each node in the Xml file:
<?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:

<?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 -->
This is just a copy of the form in the Android configuration file. Look at the specific parsing code:
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;
			}
		}
	}
}
The output results are as follows:
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.


Keywords: xml Attribute Android SDK

Added by Fredix on Sat, 22 Jun 2019 00:50:17 +0300