Interviewer: How do you dynamically determine whether the data returned by the server is Xml or Json? (Answers below)

Hence the article.

1. What is XML

XML (Extensible Markup Language): XML is a markup language used to store and transfer data. The file name extension is.xml and is case sensitive. XML defines a set of rules for encoding documents in human-readable and machine-readable formats. XML was designed to focus on the simplicity, versatility, and usability of the Internet. It is a text data format and is recommended by the W3C with strong support for different human languages through Unicode. Such as:


      

<Users> 
  <user> 
    <name>James</name>  
    <age>18</age> 
  </user>  
  <user> 
    <name>Mike</name>  
    <age>19</age> 
  </user>  
  <user> 
    <name>John</name>  
    <age>20</age> 
  </user>  
  <user> 
    <name>Peter</name>  
    <age>21</age> 
  </user> 
</Users>
Copy the code

1.1 Differences between XML and JSON

JSON (JavaScript Object Notation): A lightweight data interchange format that is completely language independent. It is based on the JavaScript programming language and is easy to understand and generate. The file name extension is. Json. Such as:

{
   "Users":[
      {
         "name":"James"."age":18
      },
      {
         "name":"Mike"."age":19
      },
      {
         "name":"John"."age":20
      },
      {
         "name":"Peter"."age":21}}]Copy the code

Differences between XML and JSON:

JSON XML
Is a JavaScript object representation Is an extensible markup language
Based on JavaScript Derived from SGML
That’s one way to represent an object Is a markup language and uses tag structures to represent data items
JSON: string, number, array, Boolean All XML data should be strings
Do not use closing tags Has start and end tags
Only UTF-8 encoding is supported Support for various encodings
Compared to XML, its files are very easy to read and understand Its documentation is relatively difficult to read and understand
No support for namespaces is provided It supports namespaces
It’s less secure It is more secure than JSON
No comments supported Support the review
Since the reference:JSON vs XML: What’s the Difference?

OK, back to the interview question above:

Interviewer: How do you dynamically determine whether the data returned by the server is Xml or Json? A: XML documents must start with “<“, so you only need to use this condition to determine. Such as: the if (s.s tartsWith (” < “)

2. How do YOU parse XML in Android

There are three ways to parse XML on Android:

  1. XmlPullParser
  2. Dom Parser
  3. SAX Parser

The following details three parsing methods and practice parsing the user_Info.xml file, parsing the contents, and displaying them. The user_info.xml file looks like this:


      

<Users>
    <user>
        <name>James</name>
        <age>18</age>
    </user>
    <user>
        <name>Mike</name>
        <age>19</age>
    </user>
    <user>
        <name>John</name>
        <age>20</age>
    </user>
    <user>
        <name>Peter</name>
        <age>21</age>
    </user>
</Users>
Copy the code

When the XML content is parsed out, it is displayed as follows:

Let’s take a look at the implementation of these three methods.

2.1 XmlPullParser

Android recommends using XMLPullParser to parse XML files because it is faster than SAX and DOM.

Methods:

  • GetEventType () : returns the type of the current event (START_TAG, END_TAG, TEXT, etc.)
  • GetName () : For START_TAG or END_TAG events, when namespaces are enabled, the (local) name of the current element, such as “Users”, “user”, “name”, “age”, is returned. When namespace processing is disabled, the original name is returned.

Event type:

  • START_DOCUMENT: Indicates that the parser is at the beginning of the document, but has not yet read anything. This event type can only be observed if getEvent() is called before the first call to the next(), nextToken(), or nextTag() methods.
  • END_DOCUMENT: Indicates that the parser is at the end of the document.
  • START_TAG: indicates the start tag.
  • END_TAG: indicates the end tag.
  • TEXT: indicates the label content.

In the user_info.xml file, the mapping is as follows:

The concrete implementation steps are as follows:

  1. Instantiate an XmlPullParser and set it up to handle XML namespaces
  2. Enter the file data stream for the parser through the setInput() method
  3. Determine the event type, call the next() method for loop parsing, and extract the tag content through the getText() method until parsing to the end of the document, END_DOCUMENT

The specific code is as follows:

class XmlPullParseTestActivity : AppCompatActivity() {
    private val userList: ArrayList<User> = ArrayList()
    private var user: User = User()

    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_xml_pull_parse_test)

        xmlParseData()
    }

    private fun xmlParseData(a) {
        try {
            val inputStream: InputStream = assets.open(USER_INFO_XML_FILE)
            val parserFactory =
                XmlPullParserFactory.newInstance()
            val parser = parserFactory.newPullParser()
            // Set the XML parser to handle namespaces
            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false)
            // Sets the input stream that the parser will process, resetting the parser state and setting the event type to the initial value START_DOCUMENT
            parser.setInput(inputStream, null)

            // Returns the current event type
            var eventType = parser.eventType
            var parseContentText = ""

            // Loop through parsing until you reach the end of the XML document
            while(eventType ! = XmlPullParser.END_DOCUMENT) {// The namespace is started, so the local name of the current element is returned, such as "Users", "user", "name", "age".
                val tagName = parser.name
                when (eventType) {
                    XmlPullParser.START_TAG -> {
                        if (tagName == USER_TAG) user = User()
                    }
                    XmlPullParser.TEXT -> {
                        // Returns the text content of the current event as a String
                        parseContentText = parser.text
                    }
                    XmlPullParser.END_TAG -> {
                        when (tagName) {
                            NAME_TAG -> user.name = parseContentText
                            AGE_TAG -> user.age = parseContentText.toInt()
                            USER_TAG -> userList.add(user)
                        }
                    }

                }
                eventType = parser.next()
            }
            // Display parsed content data
            for (user in userList) {
                val textContent = "${xmlPullParseShowTv.text} \n\n" +
                        "Name: ${user.name} \n" +
                        "Age: ${user.age} \n" +
                        "------------------\n"
                xmlPullParseShowTv.text = textContent
            }

        } catch (e: IOException) {
            e.printStackTrace()
        } catch (e: XmlPullParserException) {
            e.printStackTrace()
        }
    }

}
Copy the code

2.2 the DOM Parser

Dom Parser creates and parses XML files using an object-based approach, directly accessing parts of XML documents. Dom parsers load XML files into memory to parse XML documents, which also consumes more memory (so you can’t use Dom parsers to parse large files). The XML document is parsed from the start node to the end node.

In the Dom parser, each tag in the XML file is an Element, and the contents of the Element are a Node. If there are more than one Node in the Element, a NodeList is formed.

The mapping in user_info.xml is as follows:

Specific implementation steps:

  1. Instantiate a DocumentBuilder object and enter the document data stream using the parse() method
  2. Get the document child node with the getDocumentElement() method, and get the NodeList under that TAG with getElementsByTagName(TAG)
  3. Loop through NodeList, determine the Node type, convert Node to Element, and then repeat the previous step to retrieve node. value (the tag)

Specific code:

class DomParseTestActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_dom_parse_test)

        domParseData()
    }

    private fun domParseData(a) {
        try {
            val inputStream = assets.open(USER_INFO_XML_FILE)
            val dbFactory = DocumentBuilderFactory.newInstance()
            // Instantiate a DocumentBuilder object
            val dBuilder = dbFactory.newDocumentBuilder()

            // Parse the input stream into Document
            val doc = dBuilder.parse(inputStream)
            // Access the document element child node directly
            val element = doc.documentElement
            // Normalize the child node element
            element.normalize()

            // Retrieve all nodes under the 'user' tag
            val nodeList = doc.getElementsByTagName(USER_TAG)
            for (i in 0 until nodeList.length) {
                val node = nodeList.item(i)
                // Check if it is an element node type
                if (node.nodeType == Node.ELEMENT_NODE) {
                    // Convert node to Element in order to get node data through getElementsByTagName()
                    val theElement = node as Element
                    // Display parsed content data
                    val textContent = "${domParseShowTv.text} \n\n" +
                            "Name: ${getValue(NAME_TAG, theElement)} \n" +
                            "Age: ${getValue(AGE_TAG, theElement)} \n" +
                            "------------------\n"

                    domParseShowTv.text = textContent
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun getValue(tag: String, element: Element): String {
        // Fetch the corresponding node according to the specified label
        val nodeList = element.getElementsByTagName(tag).item(0).childNodes
        val node = nodeList.item(0)
        return node.nodeValue
    }
}
Copy the code

2.3 the SAX Parser

SAX(Simple API for XML) : Is an event-based parser. Unlike DOM parsers, SAX parsers do not create any parse trees and receive notification of events that process elements in order, starting at the top of the document and ending at the end.

Advantages: We can instruct the SAX parser to stop halfway through the document without losing the collected data. Disadvantages: The XML document cannot be accessed randomly because it is processed in a forward-only fashion.

So when is it appropriate to use SAX Parser to parse XML files?

  • You can process XML documents in a linear fashion from top to bottom.
  • The XML document to be parsed has no deep nesting.
  • You are dealing with a very large XML document whose DOM tree will consume too much memory. A typical DOM implementation uses 10 bytes of memory to represent a single byte of XML.
  • The problem you have to solve involves only one part of the XML document, that is, you only need to parse a part of the XML file.

See: Java SAX Parser-Overview

The methods we want to implement are:

  • StartDocument: Receives notification of the start of a document.
  • EndDocument: Receives notification at the end of a document.
  • StartElement: Receives notification of the start of the element.
  • EndElement: Receives notification of the end of an element.
  • Characters: receives notification of character data inside elements.

In the user_info.xml file, the mapping is as follows:

The concrete implementation steps are as follows:

  1. Instantiate a SAXParser object.
  2. Rewrite a DefaultHandler to implement the startElement, endElement, characters methods.
  3. The document input stream and Handler are passed to the SAXParser.parse() method for parsing.
class SaxParseActivity : AppCompatActivity() {
    var userList: ArrayList<User> = ArrayList()
    var user: User = User()

    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sax_parse)

        saxParseData()
    }

    private fun saxParseData(a) {
        try {
            val parserFactory: SAXParserFactory = SAXParserFactory.newInstance()
            val parser: SAXParser = parserFactory.newSAXParser()

            val inputStream: InputStream = assets.open(USER_INFO_XML_FILE)
            Parses the content of the given input stream to XML using the specified DefaultHandler.
            parser.parse(inputStream, Handler())

            // Display parsed content data
            for (user in userList) {
                val textContent = "${saxParseShowTv.text} \n\n" +
                        "Name: ${user.name} \n" +
                        "Age: ${user.age} \n" +
                        "------------------\n"
                saxParseShowTv.text = textContent
            }

        } catch (e: IOException) {
            e.printStackTrace()
        } catch (e: ParserConfigurationException) {
            e.printStackTrace()
        } catch (e: SAXException) {
            e.printStackTrace()
        }
    }

    inner class Handler : DefaultHandler() {
        private var currentValue = ""
        var currentElement = false

        /** * file starts */
        override fun startDocument(a) {
            super.startDocument()
        }

        /** * End of document */
        override fun endDocument(a) {
            super.endDocument()
        }

        /** * element start * localName: Returns the label we defined, namely: "Users","user", "name", "age" */
        override fun startElement(
            uri: String? , localName:String? , qName:String? , attributes:Attributes?). {
            super.startElement(uri, localName, qName, attributes)
            // A new node, i.e. a new user node
            currentElement = true
            currentValue = ""
            if (localName == USER_TAG) {
                user = User()
            }
        }

        /** * End of current element * localName: Returns the label we defined, namely: "Users","user", "name", "age" */
        override fun endElement(uri: String? , localName:String? , qName:String?). {
            super.endElement(uri, localName, qName)
            // The current element is parsed
            currentElement = false
            when(localName) {
                NAME_TAG -> user.name = currentValue
                AGE_TAG -> user.age = currentValue.toInt()
                // Add the first user to the userList
                USER_TAG -> userList.add(user)
            }

        }

        /** ** receives the internal character data of the element * ch: returns the contents of the label in the form of char[] * start: the initial Index of ch, that is, 0 * length: the length of the ch array */
        override fun characters(ch: CharArray? , start:Int, length: Int) {
            super.characters(ch, start, length)
            if (currentElement) {
                // Returns the contents of the label as a StringcurrentValue += String(ch!! , start, length) } } } }Copy the code

See Github: ParseXml for the full code in the above article

In fact, the biggest purpose of sharing articles is to wait for someone to point out my mistakes. If you find any mistakes, please point them out without reservation and consult with an open mind. In addition, if you think this article is good and helpful, please give me a like as encouragement, thank you ~ Peace~!

Reference Documents:

  • Android XML Parsing using SAX Parser
  • Android XML Parsing using DOM Parser
  • Android XMLPullParser Tutorial
  • Android- DOM parsing XML
  • Android– PULL for parsing XML
  • Android– SAX for parsing XML