MyException - 我的异常网
当前位置:我的异常网» XML/SOAP » XMLPULL源码解读记要 方法解读parseStartTag

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

www.MyException.Cn  网友分享于:2014-02-17  浏览:9次
XMLPULL源码解读记录 方法解读parseStartTag

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事件。

文章评论

那些争议最大的编程观点
那些争议最大的编程观点
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
如何成为一名黑客
如何成为一名黑客
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
程序员都该阅读的书
程序员都该阅读的书
为什么程序员都是夜猫子
为什么程序员都是夜猫子
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
鲜为人知的编程真相
鲜为人知的编程真相
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
中美印日四国程序员比较
中美印日四国程序员比较
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
我是如何打败拖延症的
我是如何打败拖延症的
漫画:程序员的工作
漫画:程序员的工作
一个程序员的时间管理
一个程序员的时间管理
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
老程序员的下场
老程序员的下场
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
程序员和编码员之间的区别
程序员和编码员之间的区别
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
旅行,写作,编程
旅行,写作,编程
编程语言是女人
编程语言是女人
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
10个调试和排错的小建议
10个调试和排错的小建议
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
总结2014中国互联网十大段子
总结2014中国互联网十大段子
Java程序员必看电影
Java程序员必看电影
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有