自己动手写iPhone wap浏览器之预备篇(手把手教你iphone开发 进阶篇)

作者:孙东风 2009-12-01(转载请注明出处)

在笔者的上一篇文章《玩转iPhone网络通讯之BSD Socket》中,笔者试图在iPhone平台上利用BSD Socket搭建了一个同时兼容TCP/IP和HTTP协议进行通讯的框架,而在接下来的几篇文章里,笔者将进一步完善这个网络通讯的引擎并利用这个引擎写一个简易的wap浏览器。

在iPhone的safari浏览器上并不支持WML的解析,尽管笔者也认为WML这种抱残守旧的技术被淘汰是迟早的事,但WML作为XML结构的一个“变种”进行学习还是不错的。

最近浏览器技术很热,热得笔者都摸不着头脑,前段时间金山的雷军同志也投资UCWeb,尽管笔者并不觉得浏览器技术有什么高深的技术含量抑或可进行投资的价值,其实浏览器充其量是个客户端,但是既然人家大牛看好,那笔者研究研究也不无益处,或许看完本文读者也可以拿着自己的产品去找雷军同志投资一把了:)

闲话少话,言归正传。

上面说了,WML是XML结构的一个“变种”或者说特例,既然是特例那么就可以把它当成XML来进行解析。那么做一个浏览器的任务流程就清晰了,如下:

²        封装BSD Socket进行HTTP请求。

²        将请求到的WML页面解析成XML数据结构。

²        渲染需要在界面上显示的WML标签(英文名tag)。

²        将渲染后的WML标签显示在界面上(UIView)。

其中第一条在笔者的前一篇文中《玩转iPhone网络通讯之BSD Socket》已经进行了初步的编写,当然笔者还会在下面的文章中进一步完善。

这篇文章中着重讲解WML的解析,因为WML是XML数据的特例,解析WML也就意味这解析XML。

说到解析XML,iPhone为程序员提供了很多工具比如NSXMLParser,这个类的接口定义如下:

@interface NSXMLParser : NSObject {

@private

void * _parser;

id _delegate;

id _reserved1;

id _reserved2;

id _reserved3;

}

- (id)initWithContentsOfURL:(NSURL *)url;  // initializes the parser with the specified URL.

- (id)initWithData:(NSData *)data; // create the parser from data

// delegate management. The delegate is not retained.

- (id)delegate;

- (void)setDelegate:(id)delegate;

- (void)setShouldProcessNamespaces:(BOOL)shouldProcessNamespaces;

- (void)setShouldReportNamespacePrefixes:(BOOL)shouldReportNamespacePrefixes;

- (void)setShouldResolveExternalEntities:(BOOL)shouldResolveExternalEntities;

- (BOOL)shouldProcessNamespaces;

- (BOOL)shouldReportNamespacePrefixes;

- (BOOL)shouldResolveExternalEntities;

- (BOOL)parse;  // called to start the event-driven parse. Returns YES in the event of a successful parse, and NO in case of error.

- (void)abortParsing;    // called by the delegate to stop the parse. The delegate will get an error message sent to it.

- (NSError *)parserError;      // can be called after a parse is over to determine parser state.

@end

从接口的定义中大致可以知道,这个类解析XML是采用SAX模式(Simple API for XML),而SAX是基于事件驱动的,其基本工作流程是分析XML文件流数据,每当发现一个新的元素时,就会产生一个对应的事件,并调用相应的用户处理函数。在iPhone上苹果公司采用了delegate模式,每发现一个新的元素时,就会调用相应的委托接口进行XML标签的处理。

利用SAX模式解析XML占用内存少、速度快,但用户需要把解析到的XML标签自己组合成一个树状结构,从而使程序处理比较复杂。

而对WML浏览器来说,尽管其tag并不是特别多,但是如果想完整的支持WML的tag也是一件比较枯燥的事情。所以,笔者这里采用DOM(Document Object Model)模式来解析XML文件。DOM模式在分析XML文件时,一次性的将整个XML文件流进行分析,并在内存中形成对应的树结构,同时,向用户提供一系列的接口来访问和编辑该树结构。这种方式占用内存大,速度往往慢于SAX模式,但可以给程序员提供一个面向对象的访问接口,较为方便。

XML语言的全称是可扩展标识语言(eXtensible Markup Language),具体含义顾名思义就知道了。所谓“可扩展”,那是因为HTML等语言的不可扩展,在XML里的标签都是可以自定义的,比如WML利用XML语言自定义了一套tag,于是就有了无线wap规范。

XML的可扩展性是指在相应的规范和标准上的扩展。首先格式要符合XML的基本要求,比如第一行要有声明,标签的嵌套层次必须前后一致等等,符合这些要求的文件,就算是一个合格的XML文件,称为Well-formatted。其次,XML文档因其内容的不同还必须在语义上符合相应的标准,这些标准由相应的“DTD文件”或者“Schema文件”来了定义,符合了这些定义要求的XML文件,称作Valid。

笔者在本文中采用了开源的TinyXML解析器,这个解析器不会用相应的DTD文件对XML文件进行校验,但它的体积很小,只包含两个*.h文件和四个*.cpp文件。

TinyXML是个开源的项目,更多详细的信息可以参考http://www.grinninglizard.com/tinyxml/index.html。

下载文件包后,把相应的文件导入到项目工程中,如下图:

图1

其中tinyxml.h文件包含了全部的声明,在项目中只需要包含这个文件即可。

Tinyxml.h中定义了很多结构,如下

class TiXmlNode : public TiXmlBase

{

friend class TiXmlDocument;

friend class TiXmlElement;

}

这些类对应XML中的树状结构,拿下面的XML文档为例:

<?xml version="1.0" encoding="utf-8" ?>

<!-example-->

<food>

<name>bread</name>

<price unit=”$”>1.5</price>

<description>made in China</description>

</ food >

其中整个XML文档用类TiXmlDocument表示,<food>、<name>、<price>、<description>等各自对应一个类TiXmlElement,XML文档的第一行对应类TiXmlDeclaration,第二行对应类TiXmlComment,文本“example”对应类TiXmlText,unit则是元素price的一个TiXmlAttribute属性。

把TinyXML包导入到项目后,新建一个XMLParserEx.h文件和一个XMLParserEx.cpp文件来封装XML的处理,头文件定义如下:

#ifndef _CC_XMLPARSEREX_H_

#define _CC_XMLPARSEREX_H_

#include <stdio.h>

#include "tinyxml.h"

#define INVALID_ID -1

class XMLParserEx

{

public:

static XMLParserEx* GetInstance();

static void Destroy();

void RemoveAll();

void parsexml(const char* buffer);

void ElementParser(TiXmlNode* aParent);

protected:

XMLParserEx();

~XMLParserEx();

private:

static XMLParserEx* mInstance;

};

#endif

XMLParserEx.cpp文件实现如下:

#include "XMLParserEx.h"

XMLParserEx::XMLParserEx()

{

}

XMLParserEx::~XMLParserEx()

{

RemoveAll();

}

XMLParserEx* XMLParserEx::mInstance = 0;

XMLParserEx* XMLParserEx::GetInstance()

{

if (mInstance == 0)

{

mInstance = new XMLParserEx();

}

return mInstance;

}

void XMLParserEx::Destroy()

{

if (mInstance)

{

delete mInstance;

mInstance = 0;

}

}

void XMLParserEx::RemoveAll()

{

}

void XMLParserEx::ElementParser(TiXmlNode* aParent)

{

if(aParent == NULL)

return;

TiXmlNode* aChild = aParent->FirstChild();

while(aChild)

{

printf("aChild value = %s/n",aChild->Value());

int t = aChild->Type();

if( t == TiXmlNode::ELEMENT)

{

TiXmlAttribute* attr = aChild->ToElement()->FirstAttribute();

if(attr)

{

TiXmlNode* node = aChild;

while(node)

{

while(attr)

{

printf("attr name = %s, attr value = %s/n",attr->Name(),attr->Value());

attr = attr->Next();

}

node = node->NextSiblingElement();

}

}

ElementParser(aChild);

}

else if( t == TiXmlNode::TEXT)

{

printf("aChild Value = %s/n",aChild->Value());

}

aChild = aChild->NextSibling();

}

}

void XMLParserEx::parsexml(const char* buffer)

{

TiXmlDocument* doc = new TiXmlDocument();

printf("xmlBuffer len = %d/n",strlen(buffer));

printf("xmlBuffer is = %s/n",buffer);

doc->Parse(buffer,0,TIXML_ENCODING_UTF8);

TiXmlElement* root = doc->RootElement();

printf("parse xml succeed/n");

ElementParser(root);

}

下一篇中笔者会实现BSD Socket上封装的HTTP引擎。

自己动手写iPhone wap浏览器之预备篇相关推荐

  1. 打造最强浏览器之你真的会用浏览器吗?

    前言 如果你对浏览器了解到脚本的层次,你可以选择跳过此篇文章,直接观看后两篇文章,我讲分三篇文章介绍浏览器的前世今生及生活中如何高效的使用浏览器,此篇文章主要讲解浏览器基础: 浏览器 你真的熟悉浏览器 ...

  2. [转]Android 和 iPhone 浏览器之战,第 2 部分: 为 iPhone 和 Android 构建基于浏览器的应用程序...

    简介: 本文是共两部分的系列文章 "Android 和 iPhone 浏览器之战" 的第 2 部分,主要关注为 iPhone 和 Android 开发基于浏览器的应用程序.在第 1 ...

  3. 自己动手写处理器之第一阶段(3)——MIPS32指令集架构简单介绍

    将陆续上传本人写的新书<自己动手写处理器>(尚未出版).今天是第四篇.我尽量每周四篇 1.4 MIPS32指令集架构简单介绍 本书设计的处理器遵循MIPS32 Release 1架构,所以 ...

  4. iOS学习笔记-自己动手写RESideMenu

    代码地址如下: http://www.demodashi.com/demo/11683.html 很多app都实现了类似RESideMenu的效果,RESideMenu是Github上面一个stars ...

  5. 自己动手写PHP MVC框架

    自己动手写PHP MVC框架 来自:yuansir-web.com / yuansir@live.cn 代码下载: https://github.com/yuansir/tiny-php-framew ...

  6. CefSharp内核浏览器之C#与js的互相调用

    CefSharp内核浏览器之C#与js的互相调用 js调用C#方法 1.注册js调用对象 2.创建JS类 3. HTML网页js调用 C#调用js方法 1. html写法 2. C#调用 js调用C# ...

  7. 自己动手写一个推荐系统,推荐系统小结,推荐系统:总体介绍、推荐算法、性能比较, 漫谈“推荐系统”, 浅谈矩阵分解在推荐系统中的应用...

    自己动手写一个推荐系统 废话: 最近朋友在学习推荐系统相关,说是实现完整的推荐系统,于是我们三不之一会有一些讨论和推导,想想索性整理出来. 在文中主要以工程中做推荐系统的流程着手,穿插一些经验之谈,并 ...

  8. 自己动手写工具:百度图片批量下载器

    开篇:在某些场景下,我们想要对百度图片搜出来的东东进行保存,但是一个一个得下载保存不仅耗时而且费劲,有木有一种方法能够简化我们的工作量呢,让我们在离线模式下也能爽爽地浏览大量的美图呢?于是,我们想到了 ...

  9. 浏览器之战将进入HTML5时代

    HTML5这个技术术语最近频频出现在与各大巨头相关的报道中:在iPad不支持Flash的争议声 中有它的身影,谷歌因为它放弃了对自家产品Gears的支持,而刚刚发布的IE9预览版对它的支持也成了一个热 ...

  10. 群雄逐鹿 浏览器之战将进入HTML 5时代

    HTML 5这个技术术语最近频频出现在与各大巨头相关的报道中:在iPad不支持Flash的争议声中有它的身影,谷歌因为它放弃了对自家产品Gears的支持, 而刚刚发布的IE9预览版对它的支持也成了一个 ...

最新文章

  1. 『TensorFlow』卷积层、池化层详解
  2. attr,abbr,addr三个常见的单词意思
  3. jsx怎么往js里传参数_实践Vue 3.0做JSX(TSX)风格的组件开发
  4. 实体词典 情感词典_人工智能技术落地:情感分析概述
  5. fastboot no permission
  6. 设计灵感|C4D卡通角色设计作品,你想要的模型集设都有
  7. 怎么在服务器跑sql文件,服务器mysql数据库如何运行脚本
  8. 用ssh反向隧道访问内网机器
  9. Go测试远控免杀学习
  10. android多图拼接长图并合理显示
  11. 程序猿周末副职业_早上,晚上和周末:我如何改变职业并成为程序员
  12. symbian 串行通信
  13. Windows高效文件搜索工具/Everything/Listary/uTools
  14. Vue使用vue-aplayer实现音乐播放
  15. 举头望明月打计算机术语,有关月亮的谜语和答案
  16. 第20课:技术转型的实践路线(图文篇)
  17. 菜 根 谭 [明] 洪应明
  18. CnSeu社工库免费查询_ip代理-golang测试纯真ip库与免费版ipip.net库比较
  19. 我的形码输入法[C语言] 之一:输入法的字词编码
  20. idea如何给main函数中的args[] 字符串数组赋值

热门文章

  1. F检验(ANOVA)
  2. mro python_Python之super与MRO
  3. 无线连接网络找不到计算机组,Win10电脑找不到自家Wifi无线网络解决方法 可能是无线信道问题...
  4. 【NOWCODER】- Python:列表(一)
  5. FYI | 谷歌的summer project围观一下
  6. CCF试题 201903-2 二十四点解析
  7. H5标签datalist
  8. 计算机登录界面没有用户显示不出来,笔记本电脑登录页面不显示 怎么解决
  9. 小可乐手机救砖+恢复通信录
  10. 利用Druid Monitor做数据库连接异常排查