`
fortaotao
  • 浏览: 47619 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

XMLPULL源码解读记录 方法解读parseStartTag

    博客分类:
  • XMPP
 
阅读更多

a、在parseProlog()和next()过程中会被调用,用于解析元素的定义信息。

b、代码注解

    public int parseStartTag() throws XmlPullParserException, IOException {
        //ASSUMPTION ch is past <T
        // [40] STag ::=  '<' Name (S Attribute)* S? '>'
        // [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
        ++depth; //FIXME

        //当前方法进入前,实际是已经判定过<和startNameChar的,pos-2实际是将posStart记录在<字符上。
        //因为START_TAG事件反馈后,用户通过getText取到的值是类<root>这种样式
        posStart = pos - 2;

        //空元素标识位复位为false,应该清楚这个第三方类的解析过程是线程不安全的,所以这里定义的是一个全局变量
        emptyElementTag = false;
        //元素属性数量值复位为0
        attributeCount = 0;
        //元素名称的起始绝对位置,注意绝对两字,涉及到多个字符的计算过程都需要使用绝对位置来结算,否则会出错
        //因为more()的过程中,原字符数据可能被扩展或压缩,这个时候pos来计算会得到错误值
        final int nameStart = pos - 1 + bufAbsoluteStart;
        //冒号偏移量初始值-1,一旦发现不等于-1,就说明元素名称存在冒号
        int colonPos = -1;
        char ch = buf[ pos - 1];
        //在关注命名空间的前提下,冒号不能作为元素名称的起始字符,虽然作为起始名称字符是合法的
        if(ch == ':' && processNamespaces) throw new XmlPullParserException(
                "when namespaces processing enabled colon can not be at element name start",
                this, null);
        while(true) {
            ch = more();
            //遇到非名称合法字符,则说明元素名称该收尾了,退出循环
            if(!isNameChar(ch)) break;
            if(ch == ':' && processNamespaces) {
                //关注命名空间的时候,名称中冒号最多只能出现一次
                if(colonPos != -1) throw new XmlPullParserException(
                        "only one colon is allowed in name of element when namespaces are enabled",
                        this, null);
                colonPos = pos - 1 + bufAbsoluteStart;
            }
        }

        //确保元素名称的相关信息的存储变量有足够空间
        ensureElementsCapacity();


        //记录元素原始名称、名称长度以及元素名称所在行数
        int elLen = (pos - 1) - (nameStart - bufAbsoluteStart);
        if(elRawName[ depth ] == null || elRawName[ depth ].length < elLen) {
          //?没看懂,为什么要乘以2
            elRawName[ depth ] = new char[ 2 * elLen ];
        }
        //之所以起始偏移量是nameStart-bufAbsoluteStart,是因为nameStart也是绝对位置,需要减去最新的绝对位置来获取准确的当前起点位置
        System.arraycopy(buf, nameStart - bufAbsoluteStart, elRawName[ depth ], 0, elLen);
        elRawNameEnd[ depth ] = elLen;
        elRawNameLine[ depth ] = lineNumber;

        String name = null;

        //记录处理后元素前缀和元素名称
        String prefix = null;
        if(processNamespaces) {
            if(colonPos != -1) {
                prefix = elPrefix[ depth ] = newString(buf, nameStart - bufAbsoluteStart,
                                                       colonPos - nameStart);
                name = elName[ depth ] = newString(buf, colonPos + 1 - bufAbsoluteStart,
                                                   //(pos -1) - (colonPos + 1));
                                                   pos - 2 - (colonPos - bufAbsoluteStart));
            } else {
                prefix = elPrefix[ depth ] = null;
                name = elName[ depth ] = newString(buf, nameStart - bufAbsoluteStart, elLen);
            }
        } else {

            name = elName[ depth ] = newString(buf, nameStart - bufAbsoluteStart, elLen);

        }


        //开始循环处理元素的属性信息了
        while(true) {

            while(isS(ch)) { ch = more(); } // skip additional white spaces

            if(ch == '>') {
              //与<配对,退出
                break;
            } else if(ch == '/') {
              //说明是空元素,但如果发现重复声明,抛异常
                if(emptyElementTag) throw new XmlPullParserException(
                        "repeated / in tag declaration", this, null);
                emptyElementTag = true;
                ch = more();
                if(ch != '>') throw new XmlPullParserException(
                        "expected > to end empty tag not "+printable(ch), this, null);
                break;
            } else if(isNameStartChar(ch)) {
                ch = parseAttribute();
                ch = more();
                continue;
            } else {
                throw new XmlPullParserException(
                    "start tag unexpected character "+printable(ch), this, null);
            }
            //ch = more(); // skip space
        }

        // now when namespaces were declared we can resolve them
        if(processNamespaces) {
            String uri = getNamespace(prefix);
            if(uri == null) {
                if(prefix == null) { // no prefix and no uri => use default namespace
                    uri = NO_NAMESPACE;
                } else {
                    throw new XmlPullParserException(
                        "could not determine namespace bound to element prefix "+prefix,
                        this, null);
                }

            }
            elUri[ depth ] = uri;


            //String uri = getNamespace(prefix);
            //if(uri == null && prefix == null) { // no prefix and no uri => use default namespace
            //  uri = "";
            //}
            // resolve attribute namespaces
            for (int i = 0; i < attributeCount; i++)
            {
                final String attrPrefix = attributePrefix[ i ];
                if(attrPrefix != null) {
                    final String attrUri = getNamespace(attrPrefix);
                    if(attrUri == null) {
                        throw new XmlPullParserException(
                            "could not determine namespace bound to attribute prefix "+attrPrefix,
                            this, null);

                    }
                    attributeUri[ i ] = attrUri;
                } else {
                    attributeUri[ i ] = NO_NAMESPACE;
                }
            }

            //TODO
            //[ WFC: Unique Att Spec ]
            // check attribute uniqueness constraint for attributes that has namespace!!!

            for (int i = 1; i < attributeCount; i++)
            {
                for (int j = 0; j < i; j++)
                {
                    if( attributeUri[j] == attributeUri[i]
                           && (allStringsInterned && attributeName[j].equals(attributeName[i])
                                   || (!allStringsInterned
                                           && attributeNameHash[ j ] == attributeNameHash[ i ]
                                           && attributeName[j].equals(attributeName[i])) )

                      ) {
                        // prepare data for nice error message?
                        String attr1 = attributeName[j];
                        if(attributeUri[j] != null) attr1 = attributeUri[j]+":"+attr1;
                        String attr2 = attributeName[i];
                        if(attributeUri[i] != null) attr2 = attributeUri[i]+":"+attr2;
                        throw new XmlPullParserException(
                            "duplicated attributes "+attr1+" and "+attr2, this, null);
                    }
                }
            }


        } else { // ! processNamespaces

            //[ WFC: Unique Att Spec ]
            // check raw attribute uniqueness constraint!!!
            for (int i = 1; i < attributeCount; i++)
            {
                for (int j = 0; j < i; j++)
                {
                    if((allStringsInterned && attributeName[j].equals(attributeName[i])
                            || (!allStringsInterned
                                    && attributeNameHash[ j ] == attributeNameHash[ i ]
                                    && attributeName[j].equals(attributeName[i])) )

                      ) {
                        // prepare data for nice error message?
                        final String attr1 = attributeName[j];
                        final String attr2 = attributeName[i];
                        throw new XmlPullParserException(
                            "duplicated attributes "+attr1+" and "+attr2, this, null);
                    }
                }
            }
        }

        elNamespaceCount[ depth ] = namespaceEnd;
        posEnd = pos;
        return eventType = START_TAG;
    }

 c、代码要点

c.1、如果当前要关注命名空间,则第一个字符不能是冒号。

c.2、如果当前要关注命名空间,则不能出现2个及其以上冒号。

c.3、元素名称的解析过程是直到isNameChar()为false才结束。

c.4、记录当前元素的原始名称、原始名称长度以及行号。

c.5、如果当前要关注命名空间,则记录前缀名和元素的名称。特别是无前缀名,就在elPrefix指定位置记录空;如果不关注命名空间,就仅在elName中记录元素名称。

c.6、开始进行元素属性信息的识别:>直接退出;/说明是空元素,置emptyElementTag为true(要判定是否出现了两次);isNameStartChar()为true,则进行属性信息解析parseAttribute()。

c.7、如果当前要关注命名空间,在elUri中记录命名空间的URI定义,如果有前缀,确未找到声明,则抛出异常,另外,要检查元素属性是否存在重复定义的情况;不关注命名空间,也要检查元素属性是否重复定义。

c.8、返回START_TAG事件。

分享到:
评论

相关推荐

    xmlPull源码

    XML Pull解析器在Android中的主要接口是`org.xmlpull.v1.XmlPullParser`和`org.xmlpull.v1.XmlPullParserFactory`。首先,我们需要通过`XmlPullParserFactory`创建一个`XmlPullParser`实例。工厂类提供了设置解析器...

    Xmlpull 源代码

    2. **状态机**:在XMLPull源码中,解析器内部通常使用一个状态机来跟踪解析过程。状态机在XML文档的不同部分之间切换,根据当前状态决定如何处理输入数据。 3. **解析器实例化**:在XMLPull源代码中,你需要创建...

    xmlpull-1.1.3.1.jar

    XMLPull是XML解析的一种轻量级、高效的方法,尤其适合于资源有限的环境,如Android移动平台。在Android开发中,XMLPull解析器被广泛使用,因为它不需要完整的DOM树(Document Object Model)来存储XML文档,而是通过...

    xmlpull_1_0_5解决 org/xmlpull/v1/XmlPullParserException

    4. **处理异常**:在代码中捕获`XmlPullParserException`,并提供适当的错误处理逻辑,如记录日志或向用户显示友好的错误信息。 5. **检查输入流**:确保提供的输入流有效且包含有效的XML数据。如果是从网络或文件...

    xmlpull.jar工具包

    工具包包括了:xmlpull_1_1_3_4c.jar;xmlpull_1.1.3.1.jar等。可以解析xml,导入时请将xmlpull_1_1_3_4c.jar;xmlpull_1.1.3.1.jar都导入,不然会报错。

    xmlpull(java新型xml解析技术)

    总的来说,XMLPull是Java中处理XML的一种高效方法,特别适合于移动设备或者内存受限的环境。通过事件驱动的模型,它可以有效地降低内存占用,提高解析速度,是XML解析领域的一个重要选择。在实际开发中,掌握XMLPull...

    xmlPull的jar包.zip

    使用XMLPull时,开发者首先创建一个XMLPullParser对象,然后调用其方法移动到下一个事件,如`next()`或`nextToken()`。根据返回的事件类型,比如START_TAG、END_TAG、TEXT等,执行相应的操作。这种方法使得解析器只...

    XMLPullProject(XMLPull读取)

    XMLPull是一种轻量级的解析XML文档的方法,它允许开发者在没有额外依赖库的情况下高效地处理XML数据。这个项目通过源代码示例,展示了如何在实际应用中使用XMLPull API。 XMLPull解析器的工作原理是基于事件驱动的...

    android xmlpull详细源代码

    本教程将深入探讨Android中的XMLPull解析,并通过具体的源代码分析来帮助理解其工作原理和使用方法。 首先,我们需要了解XMLPull的基本概念。XMLPull解析器是基于拉取(Pull)模式的,意味着开发者可以主动控制解析...

    XmlPull解析

    XmlPull解析是一种高效且轻量级的XML处理方式,它允许开发者通过事件驱动的模型来解析XML文档。这种解析方式不需要构建完整的XML文档对象模型(DOM),因此在内存使用和性能上都比DOM解析更优秀,尤其适用于资源有限...

    xmlpull-1.1.3.1.jar和kxml2-2.3.0.jar

    XMLPULL解析是一种轻量级、高效的处理XML文档的方法,尤其适用于资源有限的移动设备或嵌入式系统。它提供了一种编程接口,允许开发者在Java环境中读取和解析XML文档,而无需依赖完整的DOM(Document Object Model)...

    xmlpull.zip

    接着,通过迭代调用XMLPullParser的next()方法,根据返回的事件类型(如START_TAG、END_TAG等)来读取和处理XML元素。对于微信支付的个人零钱支付,可能需要解析的XML数据可能包括交易ID、支付状态、金额、时间戳等...

    xmlpull-1.1.3.1.jar和xmlpull-1.1.3.1.jar

    XMLPull是处理XML的一种轻量级、高性能的解析方式,它提供了一种统一的接口来读取XML文档,无论底层实现是基于SAX(Simple API for XML)还是DOM(Document Object Model)。XMLPull API的设计目标是减少解析XML时的...

    对xml文件进行xmlpull解析jar包

    在处理XML文件时,有多种解析方式,其中XMLPull解析是一种轻量级、高效的解析方法,适用于资源有限的环境,如移动设备。XMLPull解析器允许应用程序以拉取(pull)的方式逐个读取XML元素,而不是等待整个文档加载完毕...

    xmlpull-tests_1_0_5.jar

    这是xmlpull的测试版本,废了好长时间才找到的,如果想要下载更多版本,可以去xmlpull的官网山去下载,不嫌弃的话拿去用吧

    xml解析+kxml2+xmlpull

    在Android开发中,XML解析是处理XML文档不可或缺的技术,主要包括DOM(Document Object Model)、SAX(Simple API for XML)、PULL(Pull Parser)以及KXML2等方法。这里我们将详细探讨“xml解析+kxml2+xmlpull”...

    xmlpull_doc_src

    你可以看到如何实现XMLPull解析器的核心类,如`XMLPullParser`,它是处理XML文档的主要接口,提供了诸如next()、getName()、getText()等方法来获取XML文档的结构和内容。 "xmlpull_doc"目录则包含了XMLPull的文档...

    复杂XmlPull解析Demo

    例如,当遇到START_TAG时,我们可以记录元素名称,或者开始处理子元素;遇到TEXT时,我们可以获取元素的文本内容;遇到END_TAG时,表示当前元素结束,可能需要进行关闭操作。 3. 结束处理:当`next()`返回END_...

    kxml2-2.2.2.jar+xmlpull_1_0_5_all

    XMLPull API的核心是XMLPullParser类,它定义了一组方法,如`next()`、`getName()`和`getText()`,使得开发者可以控制解析过程并获取当前解析位置的信息。 结合KXML2和XMLPull,开发者可以在Android应用中实现灵活...

Global site tag (gtag.js) - Google Analytics