`
aaron_ch
  • 浏览: 177241 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

PHP Web Service (zhuan)

    博客分类:
  • PHP
阅读更多
允许web应用程序通过XML与其他程序通信的价值对您来说可能显而易见,但是对我来说并非如此,至少最初是这样。因此本文讲述一个示例,演示通过在应用程序中设置XML接口可以实现哪些功能。首先讲述简单的HTML前端,然后显示如何构建XML接口并添加各种阅读器(包括Ajax、RSS和Adobe Flex)。

文章应用程序
首先讲述的测试应用程序是数据库中有一个文章列表的程序。清单1显示了这个数据库。
清单 1. articles.sql
DROP TABLE IF EXISTS articles;
CREATE TABLE articles (
id INTEGER NOT NULL AUTO_INCREMENT,
title VARCHAR(255),
author VARCHAR(255),
description TEXT,
PRIMARY KEY( id ) );
INSERT INTO articles VALUES ( null,
'What I like about dogs', 'Megan Herrington',
'Everything that I love about dogs I learned in preschool' );
INSERT INTO articles VALUES ( null,
'Making action movies', 'Jack Herrington',
'How to script, produce and direct Hong Kong action flicks' );
INSERT INTO articles VALUES ( null,
'Super Paper Mario Tips', 'Lori Herrington',
'Everything you need to know to win at Paper Mario' );
INSERT INTO articles VALUES ( null,
'Why I bark', 'Oso Herrington',
'' );

该程序非常简单。它包含一个存储文章列表的简单表格;每篇文章都有标题、作者和描述。
清单2显示此表格的详细HTML前端。
清单2. articles.php
<html>
<head><title>Articles</title></head>
<body>
<?php
require_once( "DB.php" );
$db =& DB::Connect( 'mysql://root@localhost/articles1', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }
$res = $db->query( "SELECT * FROM articles" );
$rows = array();
while( $res->fetchInto($row, DB_FETCHMODE_ASSOC) ) {
?>
<div class="title"><?php echo( $row['title'] ) ?></div>
<div class="author"><?php echo( $row['author'] ) ?></div>
<?php if ( strlen( $row['description'] ) > 0 ) { ?>
<div class="description"><?php echo( $row['description'] ) ?></div>
<?php } ?>
<br/>
<?php } ?>
</body>
</html>

如果一切工作正常并且设置了此数据库,就能在浏览器中导航到此页面时显示

看到的内容并不多,但是我希望这个示例尽量简单。主要是因为后面的内容不容易处理。
提供XML接口的一个主要原因是人们不必编写清单3所示的代码。

清单 3. fetch.rb
require 'net/http'
articles = []
Net::HTTP.start('localhost', 80) { |http|
response = http.get('/ws/articles.php')
body = response.body
body.scan( /(<div class="title">.*?)<br\/>/m ) { |item|
title = item[0].scan( /<div class="title">(.*?)<\/div>/ )
author = item[0].scan( /<div class="author">(.*?)<\/div>/ )
description = item[0].scan( /<div class="description">(.*?)<\/div>/ )
title = title[0][0] if ( title[0].length > 0 )
author = author[0][0] if ( author[0].length > 0 )
description = ( description.length > 0 ) ? description[0][0] : ''
articles.push( { :title => title,
:author => author, :description => description } )
}
}
p articles

这是基于Ruby的“屏幕截取器”。这个脚本以一个大文本字符串获取页面,然后使用一组复杂的正则表达式解析页面的标题、作者和描述元素。
在命令行运行时,将看到清单4所示的代码。
清单4. 运行fetch.rb
% ruby fetch.rb
[{:author=>"Megan Herrington", :description=>"Everything that I love about dogs I
learned in preschool", :title=>"What I like about dogs"}, {:author=>"Jack
Herrington", :description=>"How to script, produce and direct Hong Kong action
flicks", :title=>"Making action movies"}, {:author=>"Lori Herrington",
:description=>"Everything you need to know to win at Paper Mario", :title=>"Super
Paper Mario Tips"}, {:author=>"Oso Herrington", :description=>"", :title=>"Why I
bark"}]
是的,它获得了数据,但是不能获得这些元素的ID,因为HTML没有ID。
您可能想知道为什么我选择使用Ruby实现。这主要是因为它很酷,并且易于阅读,可是这里却看不到这些优点。但这不是Ruby的错。屏幕截取器本身就很复杂。它们难于编写、易于出错、难以维护,即使对接口的HTML稍加修改就可能崩溃。本文中的所有屏幕截取器代码都只有一个目的:说服您对数据设置XML接口。如果您的数据很有趣,人们就能通过某种途径找到它。如果您不支持XML,当您更新站点以“美化”界面时,就会获得屏幕截取,并且触怒客户。

添加XML服务
因此,为了避免屏幕截取问题,并制作一些炫酷的程序来使用我们的数据,我将对表格编写一个XML接口,如清单5所示。
清单5. artxml.php
<?php
require_once( "DB.php" );
$db =& DB::Connect( 'mysql://root@localhost/articles1', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }
$dom = new DomDocument();
$dom->formatOutput = true;
$root = $dom->createElement( "articles" );
$dom->appendChild( $root );
$res = $db->query( "SELECT * FROM articles" );
$rows = array();
while( $res->fetchInto($row, DB_FETCHMODE_ASSOC) ) {
$art = $dom->createElement( "article" );
$art->setAttribute( 'id', $row['id'] );
$root->appendChild( $art );
$title = $dom->createElement( "title" );
$title->appendChild( $dom->createTextNode( $row['title'] ) );
$art->appendChild( $title );
$author = $dom->createElement( "author" );
$author->appendChild( $dom->createTextNode( $row['author'] ) );
$art->appendChild( $author );
$desc = $dom->createElement( "description" );
$desc->appendChild( $dom->createTextNode( $row['description'] ) );
$art->appendChild( $desc );
}
header( "Content-type: text/xml" );
echo $dom->saveXML();
?>
在命令行运行此脚本时,将获得清单6所示的输出。
清单6. 文章XML
% php artxml.php
<?xml version="1.0"?>
<articles>
<article id="1">
<title>What I like about dogs</title>
<author>Megan Herrington</author>
<description>Everything that I love about dogs I learned in
preschool</description>
</article>
<article id="2">
<title>Making action movies</title>
<author>Jack Herrington</author>
<description>How to script, produce and direct Hong Kong action
flicks</description>
</article>
...
这非常直观。有一个根文章标记,它包含一组文章标记。每个文章标记都有id属性(包含记录的数字id),以及存储相应数据的作者和描述标记。
我使用了PHP中的XML文档对象模型(Document Object Model,DOM)功能,而不是手动编写标记。这样DOM将为我处理所有XML节点平衡和编码工作。这是确保页面返回的XM总是有效的简便方式。强烈推荐使用XML DOM功能来输出XML。所有主要的web语言都支持构建和导出XML DOM。
获取XML
上文中我展示了从HTML中提取数据的HTML和Ruby代码。既然拥有了此XML服务,下面将观察获得相同数据的Ruby代码片断,但是这次使用XML语言。清单7显示了XML提取代码。
清单7. fetchxml.rb
require 'net/http'
require 'rexml/document'
articles = []
Net::HTTP.start('localhost', 80) { |http|
response = http.get('/ws/artxml.php')
body = response.body
doc = REXML::Document.new body
doc.each_element( '/articles/article' ) { |art|
articles.push( {
:id => art.attributes['id'],
:title => art.elements['title'].text,
:author => art.elements['author'].text,
:description => art.elements['description'].text
} )
}
}
p articles

这更简单。仍然能以相同的方式获得页面,但是将页面内存提供给REXML库,并使用XML功能轻松快捷地获得id、标题、作者和描述数据。此代码易于阅读、易于维护并且不会崩溃,除非XML格式发生变化,但这不太可能。
作为比较,我使用C#编写了相同的代码以显示如何使用两种不同的语言阅读单个数据源。如清单8所示。
清单8. WebServiceTest.cs
using System;
using System.IO;
using System.Net;
using System.Xml;
namespace wstest1
{
class WebServiceTest
{
[STAThread]
static void Main(string[] args)
{
HttpWebRequest r = (HttpWebRequest)WebRequest.Create(
"http://localhost/ws/artxml.php" );
WebResponse res = r.GetResponse();
string sPage;
StreamReader reader = new StreamReader( res.GetResponseStream() );
sPage = reader.ReadToEnd();
reader.Close();
res.Close();
XmlDocument doc = new XmlDocument();
doc.LoadXml( sPage );
foreach( XmlElement elArticle in doc.GetElementsByTagName( "article" ) )
{
string sTitle = (elArticle.SelectSingleNode( "title" )).InnerXml;
string sAuthor = (elArticle.SelectSingleNode( "author" )).InnerXml;
string sDescription = (elArticle.SelectSingleNode( "description"
)).InnerXml;
int nID = Int32.Parse( elArticle.Attributes["id"].Value );
}
}
}
}

解决了本文中最难以处理的部分后,下面应该讨论有趣的事情了,比如以其他方式使用XML可以实现什么功能。
在XSLT中使用XML
等等,我刚才是不是说最难以处理的部分已经解决了?哦,不好意思,还有另外一项。结果发现使用XML Style Sheet或XSL可以快速设置XML数据格式。清单9所示的代码设置web服务(从articles.php页面写入到HTML)所返回的XML代码的格式。
清单9. articles.xsl
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/TR/xhtml1/strict">
<xsl:output method="html" indent="yes" encoding="iso-8859-1" />
<xsl:template match="/">
<html>
<head><title>Article list</title></head>
<body>
<xsl:for-each select="/articles/article">
<div class="title"><xsl:value-of select="title"/></div>
<div class="author"><xsl:value-of select="author"/></div>
<xsl:if test="string-length( description ) &gt; 0">
<div class="description"><xsl:value-of select="description"/></div>
</xsl:if>
</xsl:for-each>
</body></html>
</xsl:template>
</xsl:stylesheet>

读起来有点不太容易,但是这是您的XSL。基本上,XSL是模式匹配器,我定义了匹配传入XML树的根标记的XSL模板。它输出HTML报头,然后使用for-each循环遍历每篇文章,并输出标题、作者和描述的值(如果有)。
此样式表可以附加到XML输出本身,大多数浏览器将使用它将XML呈现到HTML以自动显示。怎么样!

Ajax
从应用程序中导出XML的最可能的理由是为了能够在web客户端中使用。客户端的JavaScript可以在加载页面之后从服务器请求XML,并以它所选择的任何方式(经常根据用户输入动态更改)呈现,并且不需要刷新页面。
清单10显示了一个基于Ajax的简单表格,它呈现来自XML feed的数据。
清单10. ajax.html
<html><head>
<script src="prototype.js"></script>
</head>
<body><table id="articles"></table>
<script>
new Ajax.Request( 'artxml.php', {
method: 'get',
onSuccess: function( transport ) {
var artTags = transport.responseXML.getElementsByTagName( 'article' );
for( var a = 0; a < artTags.length; a++ ) {
var author =
artTags[a].getElementsByTagName('author')[0].firstChild.nodeValue;
var title = artTags[a].getElementsByTagName('title')[0].firstChild.nodeValue;
var description =
artTags[a].getElementsByTagName('description')[0].firstChild.nodeValue;
var elTR = $('articles').insertRow( -1 );
var elTD1 = elTR.insertCell( -1 );
elTD1.innerHTML = author;
var elTD2 = elTR.insertCell( -1 );
elTD2.innerHTML = title;
var elTD3 = elTR.insertCell( -1 );
elTD3.innerHTML = description;
}
}
} );
</script></body></html>

此代码使用Prototype.js库从数据库访问数据,然后使用浏览器中的XML DOM功能访问作者、标题和描述字段。然后,使用HTML DOM函数针对数据集中的每篇文章向“articles”表格添加新行和单元格。

这是非常基础的示例,但是完全不必向服务器端请求额外的数据,即可轻松地设想添加客户端排序或搜索。

使用Flex访问XML
下一代内容丰富的Internet应用程序框架(如Adobe Flex)是基于XML产生和发展起来的。因此可以轻松使用和显示XML数据。观察清单11所示的示例Flex应用程序。
清单11. wstest.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
<mx:XML id="articles" source="http://localhost/ws/artxml.php" />
<mx:DataGrid dataProvider="{articles..article}" width="400">
<mx:columns>
<mx:Array>
<mx:DataGridColumn dataField="author" headerText="Author" />
<mx:DataGridColumn dataField="title" headerText="Title" />
<mx:DataGridColumn dataField="description" headerText="Description" />
</mx:Array>
</mx:columns>
</mx:DataGrid>
</mx:Application>
其中并没有实际代码,仅仅是对XML数据源的引用,然后此数据源被传送到DataGrid控件。

是不是很酷?实现此功能不需要任何代码。这只是Flex 和ActionScript使用XML可以实现的基本功能。ActionScript有一个内置的语言扩展,名为E4X。借助E4X,可以像使用“点标注”语法一样简单地导航XML文档树。这意味着没有太多沉闷的XML DOM方法,仅仅是直观对象和数组引用,就像内存中有任何其他数据结构一样。

标准化
我使用了仅适于本示例的XML风格。但是也可以使用标准XML格式实现,如RSS。清单12中的代码以RSS格式显示了相同数据库输出。

清单12. artrss.php
<?php
require_once( "DB.php" );
$db =& DB::Connect( 'mysql://root@localhost/articles1', array() );
if (PEAR::isError($db)) { die($db->getMessage()); }
$dom = new DomDocument();
$dom->formatOutput = true;
$rss = $dom->createElement( "rss" );
$rss->setAttribute( "version", "0.91" );
$dom->appendChild( $rss );
$root = $dom->createElement( "channel" );
$rss->appendChild( $root );
$rtitle = $dom->createElement( "title" );
$rtitle->appendChild( $dom->createTextNode( "Article list" ) );
$root->appendChild( $rtitle );
$rdesc = $dom->createElement( "description" );
$rdesc->appendChild( $dom->createTextNode( "The article list" ) );
$root->appendChild( $rdesc );
$res = $db->query( "SELECT * FROM articles" );
$rows = array();
while( $res->fetchInto($row, DB_FETCHMODE_ASSOC) ) {
$art = $dom->createElement( "item" );
$root->appendChild( $art );
$title = $dom->createElement( "title" );
$title->appendChild( $dom->createTextNode( $row['title'] ) );
$art->appendChild( $title );
$title = $dom->createElement( "link" );
$title->appendChild( $dom->createTextNode(
"http://myhost/showarticle.php?id=".$row['id'] ) );
$art->appendChild( $title );
$desc = $dom->createElement( "description" );
$desc->appendChild( $dom->createTextNode( $row['description'] ) );
$art->appendChild( $desc );
}
header( "Content-type: text/xml" );
echo $dom->saveXML();
?>

此方法的好处在于,除了可以阅读XML的任何自定义代码之外,还可以使用所有的RSS工具。例如,可以在feed中指向我的Firefox浏览器,就会创建可以放到工具栏并检查更新的“活动书签”,
 
当然,不是所有数据都能方便地设置为RSS格式,这没什么问题。但是如果可以成为RSS、RDF或任何其他方便的XML格式。那么最好遵循这些格式,而不是自己发明。

结束语
希望本文能够使您以正确的角度理解应用程序的web服务。我知道并没有讲述所有REST、XML/RPC或SOAP基础知识。有很多文章讨论过这些技术,多年以来,技术人员已经历过很多基于标准的噩梦。相反,我希望展示从应用程序中获得XML数据并以实用的方式使用它是件多么轻松的事情。如果我成功了,请写信告知我并展示从您的应用程序中提取的XML数据。也许我们可以使用其他web服务一起完成一个mash-up。
分享到:
评论

相关推荐

    zhuan 2.zip

    移动适配是现代Web开发的关键,此项目特别指出它支持“移动端”。这意味着代码可能采用了响应式设计,能够自适应不同屏幕尺寸的手机和平板设备,确保在各种设备上都能正常运行和展示。开发者可能使用了媒体查询...

    gssdgv-zhuan-ke-master_java_

    《蚂蚁集团开源的Java研发框架——gssdgv-zhuan-ke-master_java_详解》 在现代软件开发中,高效、稳定且易维护的框架是项目成功的关键因素之一。蚂蚁集团作为全球知名的金融科技公司,其开源的Java研发框架——...

    自媒体新媒体软件工具自媒体zhuan钱秘诀资料

    自媒体新媒体软件工具自媒体zhuan钱秘诀资料

    zhuan_java_untilgw8_android_

    标题 "zhuan_java_untilgw8_android_" 暗示了这是一个关于使用Java语言在UntilGW8平台上开发Android游戏的项目,特别是一款简单的打砖块游戏。在这个项目中,我们可以深入学习到Java编程语言、Android应用开发的基础...

    PHP 汉字转换拼音

    在IT行业中,尤其是在Web开发领域,PHP是一种广泛使用的服务器端脚本语言。有时,我们可能需要将汉字转换为拼音,这在处理中文数据、搜索引擎优化(SEO)或为不熟悉汉字的用户提供帮助时非常有用。PHP提供了一些库和...

    Map_out.rar_Map o_mapgis_mapgis noteo_mapgis zhuan jpg_out

    "Map o_mapgis_mapgis noteo_mapgis zhuan jpg_out"这部分可能是描述了这个压缩包的主要功能或者过程,即MapGIS的二次开发功能,用于将MapGIS的地图数据转换成JPG格式的光栅图像。"o_mapgis_mapgis noteo_mapgis...

    php汉字转拼音 降汉字转换为拼音,utf-8

    // 输出:hanzi zhuan pinyin ``` 总的来说,PHP汉字转拼音是处理中文数据时不可或缺的技术,而UTF-8编码则保证了在不同系统和平台间数据的兼容性。通过选择合适的库并理解其工作原理,开发者可以高效地实现这一...

    z zhuan sec_EH4_EH4Z文件转SEC文件_

    标题中的"z zhuan sec_EH4_EH4Z文件转SEC文件_"表明我们正在处理一个涉及到将EH4或EH4Z格式的文件转换为SEC格式的议题。这个过程可能涉及到特定的工具、编程语言或者协议,尤其是在嵌入式系统中,这些文件格式通常与...

    ann(zhuan).rar_ANN

    本人转的别人写的人工神经网络的学习体会与感受,真是受益匪浅啊!

    soho网络zhuan钱的体会.doc

    文档标题和描述中提到的是关于个人通过SOHO(Small Office Home Office)网络工作赚钱的体验,标签为“技术”,这表明讨论的核心是如何利用网络技术和自我经营来赚取收入。部分内容中,作者分享了自己从怀疑到加入...

    2.6.14 内核移植说明文档(zhuan)

    ### 2.6.14 内核移植与YAFFS文件系统支持详解 #### 一、2.6.14 内核移植步骤 **1.... - **背景**: 如果您使用的是其他人移植好的内核版本,则在开始编译之前应该清除中间文件。这是为了避免因使用的交叉编译工具不同...

    zhuan-su-eliang.rar_labview 测_labview 测速_labview测速_labview转速测量_转

    在给定的“zhuan-su-eliang.rar”压缩包中,包含了一个名为“zhuan su eliang.vi”的虚拟仪器(VI),这显然是一款用于转速测量的应用程序。 转速测量是机械工程、汽车工业、电力系统等领域中常见的技术需求。...

    zhuan8.rar_kinect_人工势场法

    主要用于路径规划,程序读入之初,需要先读入Kinect相机拍摄的深度图像。

    ban-zhuan.zip_JAVA穷举法搬砖_搬砖_用JAVA穷举法

    在给定的“ban-zhuan.zip_JAVA穷举法搬砖”主题中,我们面对的是一个数学问题,该问题与实际的砖块分配有关。36块砖需要36个人来搬运,其中包括男性、女性和小孩,他们各自有不同的搬运能力。男性每次能搬4块砖,...

    XUAN-ZHUAN-led.zip_旋转LED_旋转LED 自适应_自适应旋转LED

    "XUAN-ZHUAN-led.zip_旋转LED_旋转LED 自适应_自适应旋转LED"这个压缩包文件内容是关于实现旋转LED自适应转速的程序,其核心目标是让LED屏幕上的字幕能够流畅地滚动,并根据设备的转速自动调整滚动速度,以保持最佳...

    C#代码重构 - Mr.Fu _Zhuan.mobi

    重构是迅速发现并修复有问题的代码的一种高效的方式。在《代码重构(c # & asp.net版)》中首次提供了在c#和asp.net中进行重构的专业方法,您将学习如何运用重构技术管理和修改代码

    snake-master-cuda8-zhuan_pt.tar

    Deep Snake for Real-Time Instance Segmentation pytorch1.0 cuda8转6个pt

    zhuan-kai-fa

    标题“zhuan-kai-fa”似乎是在简写或拼音化表示“专开发”,这可能是指专门的软件开发或者技术开源项目。由于没有具体的标签信息,我们将从一般软件开发的角度来探讨相关知识点。 在软件开发领域,"专开发"可以涵盖...

    编码器计数

    bai_zhuan=(int)zhuan/100; shi_zhuan=(int)zhuan0/10; ge_zhuan=(int)zhuan; write_data(table[bai_fen]); write_data(table[shi_fen]); write_data(table[ge_fen]); write_data(table[12]); write...

    pdfzhuantxt.rar_pdf txt_pdf zhuan txt_pdfzhuant_pdf转txt_txt转pdf

    PDF转TXT格式是一种常见的文档转换需求,特别是在处理大量文本数据时。这个名为“pdfzhuantxt.rar”的压缩包提供了一个小程序,能够帮助用户将PDF文件转换为纯文本(TXT)格式。PDF(Portable Document Format)是...

Global site tag (gtag.js) - Google Analytics