`

使用 PHP 将 SQL 转换为 XML

    博客分类:
  • php
阅读更多

 http://www.ibm.com/developerworks/cn/xml/x-query2xml/index.html
developerWorks 中国  ]  XML | Open source  ]

使用 PHP 将 SQL 转换为 XML
轻松地将数据库查询结果转换为 XML 文档
 
 
  文档选项
   将此页作为电子邮件发送
 
 


 
级别: 中级

Vikram Vaswani, 创始人, Melonfire


2007 年 9 月 20 日

您是否想过用一种简单的方法将 SQL 结果集转换为 XML?PEAR 包 XML_Query2XML 提供的一种全面性框架可以有效地将数据库查询结果转换为可定制的 XML 文档。本文将介绍这个包,并演示有用的实际应用程序,包括将它与 XSL 和 XPath 结合使用,并与来自外部 Web 服务的数据相结合,创建数据库转储文件。
简介

也许您曾经听过 PEAR,PHP 扩展和应用库(PHP Extension and Application Repository)。这个社区推动的项目的目标是,提供一个广泛的、高质量代码的开源库,协助 PHP 开发人员快速开发应用程序。与 Perl 的 CPAN 存储库的概念类似,PEAR 一直以来都是我首先关注的有趣、有用的 PHP+XML 小部件。这些部件包括:XML_Serializer 类,用于方便地将 PHP 数据结构序列化为 XML 对象;XML_XUL 类,为构造 Mozilla XUL 应用程序提供了一个 API;XML_SVG 类,为通过编程构造 SVG 格式的向量图提供方法;等等。

在本文中,我还将向您介绍 PEAR 的 XML 部分的另一个成员,XML_Query2XML 类。此类提供了一个 API,用于快速有效地将 SQL 结果集转换为格式良好的 XML。如果稍加创新,通过 XSL 转换可以很轻松地将此输出转换为其他格式,或与其他基于 XML 的应用程序集成。

 

 


 回页首
 

 

安装所需的软件

XML_Query2XML 包由 Lukas Feiler 积极地开发和维护,并在 LGPL 许可下发布给 PHP 社区。它需要使用 PHP 5.0(或更高版本)运行。安装它的最简单的方法是使用 PEAR 自动安装程序,此程序应该默认包含在 PHP 构建中。要安装此包,只需在 shell 提示中发出以下命令即可:

shell]pear install XML_Query2XML

PEAR 安装程序将连接到 PEAR 包服务器,下载此包并将其安装到系统中合适的位置。

要手动安装此包,请访问它在 PEAR Web 站点上的主页,下载包归档文件并手动地将这些文件解压缩到所需位置。注意,手动安装过程要求用户对 PEAR 的包组织结构有一些了解。

现在,您还应该意识到一些其他依赖项:

XML_Query2XML 使用 DB、MDB2 或 ADOdb 数据库的抽象层与目标 RDBMS 通信,并因此要求存在这样一个抽象层,而且进行了正确安装,还要求有一个合适的数据库驱动程序。本文所给出的例子使用了 MDB2 抽象层(PEAR 包树的一部分)和它的 MySQL driver MDB2_Driver_mysql。正如前面所提到的,您可以使用 PEAR 自动安装程序安装这两个包,另外,您也可以从 PEAR Web 站点下载它们。
本文中的例子使用 MySQL 的示例数据库 world,其中包含了各种预填充的链接表,表中存储了城市数据和国家数据。有关获取和设置 world 数据库的指导,可以参考本文的 参考资料 部分。
本文中的例子要求 PHP 构建能够支持 PHP 的 DOM、XSL 和 SimpleXML 函数。PHP 5.x 中默认支持这些函数。
要求具有使用 PHP 的 DOM 和 SimpleXML 函数以及 XML、XPath、XSL 技术的实际经验。
有关这些不同组件的信息及下载链接,请参阅 参考资料。

本文中的所有例子都已使用 XML_Query2XML Version 1.2.1 进行了测试。

 

 


 回页首
 

 

将 SQL 转换为 XML

成功安装完所有需要的组件后,就可以使用下面的示例 PHP 脚本开始探索 XML_Query2XML:


清单 1. 示例 SQL-to-XML 转换
               
[?php
// include required files
include 'XML/Query2XML.php';
include 'MDB2.php';

try {
    // initialize Query2XML object
    $q2x = XML_Query2XML::factory(MDB2::factory('mysql://root:pass@localhost/world'));
   
    // generate SQL query
    // get results as XML
    $sql = "SELECT * FROM Country";
    $xml = $q2x-]getFlatXML($sql);
   
    // send output to browser
    header('Content-Type: text/xml');
    $xml-]formatOutput = true;
    echo $xml-]saveXML();
} catch (Exception $e) {
    echo $e-]getMessage();
}
?]
        


这段脚本演示了 XML_Query2XML 类的基本用法。首先,脚本包含了 XML_Query2XML 和 MDB2 类文件,然后通过它的 factory() 方法初始化了一个 MDB2 抽象层实例。此方法接受 DSN 作为输入,其中包含了关于 RDBMS 类型、RDBMS 用户名和密码,以及目标数据库名称的信息。得到的 MDB2 实例然后用于初始化 XML_Query2XML 实例,后者由 $q2x 对象表示。

构造 DSN 并创建 XML_Query2XML 对象实例后,即可实际对 RDBMS 执行 SQL 查询并将结果转换为 XML。通过 XML_Query2XML 的 getFlatXML() 方法可以完成这一任务,而该方法经常用于简单的 SELECT 类型的查询。此方法的输出是格式良好的 XML 文档,其中对 SQL 结果集进行了编码。生成的 XML 结果类似于:


清单 2. 由清单 1 生成的 XML 输出(经过了简化)
               
[?xml version="1.0" encoding="UTF-8"?]
[root]
  [row]
    [code]AFG[/code]
    [name]Afghanistan[/name]
    [continent]Asia[/continent]
    [region]Southern and Central Asia[/region]
    [surfacearea]652090.00[/surfacearea]
    [indepyear]1919[/indepyear]
    [population]22720000[/population]
    [lifeexpectancy]45.9[/lifeexpectancy]
    [gnp]5976.00[/gnp]
    [gnpold][/gnpold]
    [localname]Afganistan/Afqanestan[/localname]
    [governmentform]Islamic Emirate[/governmentform]
    [headofstate]Mohammad Omar[/headofstate]
    [capital]1[/capital]
    [code2]AF[/code2]
  [/row]
  [row]
    [code]NLD[/code]
    [name]Netherlands[/name]
    [continent]Europe[/continent]
    [region]Western Europe[/region]
    [surfacearea]41526.00[/surfacearea]
    [indepyear]1581[/indepyear]
    [population]15864000[/population]
    [lifeexpectancy]78.3[/lifeexpectancy]
    [gnp]371362.00[/gnp]
    [gnpold]360478.00[/gnpold]
    [localname]Nederland[/localname]
    [governmentform]Constitutional Monarchy[/governmentform]
    [headofstate]Beatrix[/headofstate]
    [capital]5[/capital]
    [code2]NL[/code2]
  [/row]
  [row]
    [code]ANT[/code]
    [name]Netherlands Antilles[/name]
    [continent]North America[/continent]
    [region]Caribbean[/region]
    [surfacearea]800.00[/surfacearea]
    [indepyear][/indepyear]
    [population]217000[/population]
    [lifeexpectancy]74.7[/lifeexpectancy]
    [gnp]1941.00[/gnp]
    [gnpold][/gnpold]
    [localname]Nederlandse Antillen[/localname]
    [governmentform]Nonmetropolitan Territory of
    The Netherlands[/governmentform]
    [headofstate]Beatrix[/headofstate]
    [capital]33[/capital]
    [code2]AN[/code2]
  [/row]
  ...
[/root]
        


仔细查看一下上面的 XML 输出可以看到一个清晰的结构。来自 SQL 结果集的每条记录都表示为一个 [row] 元素,而每条记录的单个字段则嵌入到每个相应的 [row] 中。被嵌入元素的名称与被查询表中的字段名称对应,而文档元素 — XML 树的根 — 被相应地命名为 [root]。

 

 


 回页首
 

 

使用 XSL 转换 XML 输出

当然,从 SQL 查询生成 XML 通常只是完成了一半任务;剩下的一半任务是使用生成的 XML。使用 XML 文档可以做很多工作,但是其中最重要的一项就是使用 XSL Transformation 将其转换为一些其他格式,比如 HTML 或 RSS。明白这一点后,我们来快速制作一个 XSL 样式表,将 清单 2 的 XML 输出转换为一个简单的 HTML 页面。


清单 3. 一个 XSL 样式表
               
[?xml version="1.0" encoding="UTF-8"?]
[xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"]
    [xsl:template match="/root"]
        [html]
            [head]
                [style type="text/css"]
                td { text-align: center; padding: 3px; }
                .head { font-style: italic; }
                [/style]
            [/head]
            [body]
                [table border="1"]
                    [thead]
                        [tr]
                            [xsl:for-each select="row[1]/*"]
                                [td class="head"]
                                    [xsl:value-of select="local-name(.)"/]
                                [/td]
                            [/xsl:for-each]
                        [/tr]
                    [/thead]
                    [tbody]
                        [xsl:apply-templates/]
                    [/tbody]
                [/table]
            [/body]
        [/html]
    [/xsl:template]

    [xsl:template match="row"]
        [tr]
            [xsl:apply-templates/]
        [/tr]
    [/xsl:template]

    [xsl:template match="row/*"]
        [td]
            [xsl:value-of select="."/]
        [/td]
    [/xsl:template]
[/xsl:stylesheet]
        


在清单 4 中您会看见修改后的 PHP 脚本,它现在使用 PHP 的 XSL 函数转换 XML_Query2XML 生成的输出:


清单 4. 使用 XSL 转换 SQL-to-XML 输出
               
[?php
// include required files
include 'XML/Query2XML.php';
include 'MDB2.php';

try {
    // initalize Query2XML object
    $q2x = XML_Query2XML::factory(MDB2::factory('mysql://root:pass@localhost/world'));
   
    // generate SQL query
    // get results as XML
    $sql = "SELECT * FROM Country";
    $xml = $q2x-]getFlatXML($sql);
   
    // read XSL stylesheet data
    $xsl = new DOMDocument;
    $xsl-]load('country.xsl');
   
    // initialize XSLT engine
    $xslp = new XSLTProcessor;
   
    // attach XSL stylesheet object
    $xslp-]importStyleSheet($xsl);
   
    // perform transformation
    header('Content-Type: text/html');
    echo $xslp-]transformToXML($xml);
} catch (Exception $e) {
    echo $e-]getMessage();
}
?]
        


这段脚本的第一部分与 清单 1 类似;它所生成的 XML 文档包含了 SQL 查询的结果并将其作为 DOMDocument 实例存储在 $xml 中。接下来,初始化 XSLTProcessor 类的一个实例,并使用类的 importStyleSheet() 方法导入 XSL 的样式表。transformToXML() 方法接受源 XML 数据作为输入参数,然后使用 XSL 样式表中指定的规则将 XML 文档转换为 HTML 页面。

图 1 给出了输出结果:


图 1. 由清单 4 生成的 HTML 文档
XSL 转换后生成的 HTML 页面




回页首

定制 XML 输出

前面示例中所展示的 getFlatXML() 方法在只需要快速实现 SQL-to-XML 转换时很有用。但是,如果您需要执行某些更复杂的操作时 — 例如,将某些结果集字段作为属性而不是元素显示,或定义自己的元素名称 — 您应该使用 XML_Query2XML 中的 getXML() 方法。此方法让您能够广泛地定制输出 XML,包括其结构和样式。

清单 5 中给出了一个例子:


清单 5. 定制 SQL-to-XML 输出
               
[?php
// include required files
include 'XML/Query2XML.php';
include 'MDB2.php';

try {
    // initalize Query2XML object
    $q2x = XML_Query2XML::factory(MDB2::factory('mysql://root:pass@localhost/world'));
   
    // generate SQL query
    // get results as XML
    $sql = "SELECT * FROM Country";
    $xml = $q2x-]getXML($sql, array(
            'idColumn' =] 'code',
            'rootTag' =] 'countries',
            'rowTag' =] 'country',
            'attributes' =] array('code'),
            'elements' =] array('name', 'continent', 'area' =] 'surfacearea')
        )   
    );
   
    // send output to browser
    header('Content-Type: text/xml');
    $xml-]formatOutput = true;
    echo $xml-]saveXML();
} catch (Exception $e) {
    echo $e-]getMessage();
}
?]
        


getXML() 方法接受两个参数:待执行的 SQL 查询,和定义 XML 输出格式的一组选项。表 1 说明了前一个清单中每个选项的含义:


表 1. getXML() 方法的选项
选项 控制内容
rootTag 文档元素的名称(默认:root)
rowTag 表示每个结果行的元素的名称(默认:row)
idColumn 结果集的主键字段
attributes 一个显示为 XML 属性的字段列表
elements 一个显示为 XML 元素的字段列表

清单 6 给出了清单 5 的脚本的输出:


清单 6. 由清单 5 生成的 XML 输出(经过了简化)
               
[?xml version="1.0" encoding="UTF-8"?]
[countries]
  [country code="AFG"]
    [name]Afghanistan[/name]
    [continent]Asia[/continent]
    [area]652090.00[/area]
  [/country]
  [country code="NLD"]
    [name]Netherlands[/name]
    [continent]Europe[/continent]
    [area]41526.00[/area]
  [/country]
  [country code="ANT"]
    [name]Netherlands Antilles[/name]
    [continent]North America[/continent]
    [area]800.00[/area]
  [/country]
  ...
[/countries]
        


注意,这个 XML 文档没有包含来自 SQL 结果集的所有字段,而是只包含了 elements 和 attributes 数组中所指定的那些字段,而且 attributes 数组中指定的字段显示为每个 [country] 元素的属性,而不是子节点。

您还会记得,输出 XML 中的元素和属性名称默认为相应的字段名称。但是,当使用 getXML() 方法时,您可以通过在 attributes 和 elements 数组中指定替代值作为键-值对,修改这些默认名称。例如:SQL 结果集中的 surfacearea 字段在 XML 输出中简单地显示为 [area] 元素。

有关如何定制 getXML() 方法的输出的示例,请查看 XML_Query2XML 手册(参阅 参考资料)。

 

 


 回页首
 

 

使用 SQL 连接

XML_Query2XML 还提供了一个框架,利用该框架可以使用 XML 将一个结果集的内容嵌入到另一个结果集中。此特性在处理连接或以某种方式链接的查询最为常用;如果您出于性能考虑,需要将一个大查询分解为多个小查询,使用该框架也很方便。

为了更好地理解这一点,我们回到 world 数据库并考虑它的两个表 Country 和 City,此二者通过 code 外键相互链接在一起。

现在,假设您希望生成一个 XML 文档树,它将多个 [city] 元素嵌入到外部的 [country] 元素中。我们再假设您希望将输出限制为每个国家的人口最多的五个城市,并且您希望字段值表示为属性而不是元素。简言之,假设您需要一个如下所示的 XML 文档:


清单 7. SQL 连接之后的预期 XML 输出(经过了简化)
               
[?xml version="1.0" encoding="UTF-8"?]
[countries]
  [country code="IND" name="India" region="Southern and Central Asia"]
    [cities]
      [city name="Mumbai (Bombay)" district="Maharashtra" population="10500000"/]
      [city .../]
      [city .../]
      [city .../]
      [city .../]
    [/cities]
  [/country]
  [country ...]
      ...
  [/country]
  ...
[/countries]
        


清单 8 中的代码用于生成这样的嵌套 XML 文档:


清单 8. 从 SQL 连接创建定制的 XML 输出
               
[?php
// include required files
include 'XML/Query2XML.php';
include 'MDB2.php';

try {
    // initalize Query2XML object
    $q2x = XML_Query2XML::factory(MDB2::factory('mysql://root:pass@localhost/world'));
   
    // generate SQL query
    // get results as XML
    $sql_1 = "SELECT * FROM Country";
    $sql_2 = "SELECT * FROM City WHERE CountryCode = ? ORDER BY Population DESC LIMIT 5";
    $xml = $q2x-]getXML($sql_1, array(
            'idColumn' =] 'code',
            'rootTag' =] 'countries',
            'rowTag' =] 'country',
            'attributes' =] array('code', 'name', 'continent'),
            'elements' =] array('cities' =] array(
                'sql' =] array('data' =] array('code'), 'query' =] $sql_2),
                'idColumn' =] 'id',
                'rootTag' =] 'cities',
                'rowTag' =] 'city',
                'attributes' =] array('name','district','population'))
            )
        )   
    );
   
    // send output to browser
    header('Content-Type: text/xml');
    $xml-]formatOutput = true;
    echo $xml-]saveXML();
} catch (Exception $e) {
    echo $e-]getMessage();
}
?]
        


此处要注意的关键是 elements 数组。清单 5 中该数组只包含一个显示为元素的结果集字段列表,而在这里,该数组执行了一个复杂得多的函数。它首先定义了一个新元素 [cities],然后将它链接到一个包含名称-值对的选项数组。此选项数组中的惟一新键为 sql 键,它定义了运行内部 SQL 查询以填充 [cities] 元素。

有必要花点时间了解一下这个 sql 键。此键被链接到一个关联数组,数组本身包含了两个键:

data,指定从外部 SQL 查询导入的字段
query,指定填充 [cities] 元素时要运行的内部 SQL 查询
注意,第二个 SQL 查询包含了一个问号(?)占位符 — 运行时,此占位符被 data 数组中指定的字段当前值替代。或者,使用一个实际的例子,如果外部查询返回的记录包含 code 字段的 'IND' 值,则这个 'IND' 值随后将被内插到内部查询中,替代 ? 占位符。

XML_Query2XML 的神奇之处现在应该清楚了。您可以使用单独的 SQL 查询填充每个 elements 数组,从而允许 SQL 结果集被嵌入到无限制的深度。此外,因为每个 elements 数组可以引用父查询的字段,所以可以创建一系列链式查询(与 SQL 连接相似),通过特定的命名字段相互链接。

输出结果如下:


清单 9. 由清单 8 生成的 XML 输出(经过了简化)
               
[?xml version="1.0" encoding="UTF-8"?]
[countries]
  [country code="AFG" name="Afghanistan" continent="Asia"]
    [cities]
      [city name="Kabul" district="Kabol" population="1780000"/]
      [city name="Qandahar" district="Qandahar" population="237500"/]
      [city name="Herat" district="Herat" population="186800"/]
      [city name="Mazar-e-Sharif" district="Balkh" population="127800"/]
    [/cities]
  [/country]
  [country code="NLD" name="Netherlands" continent="Europe"]
    [cities]
      [city name="Amsterdam" district="Noord-Holland" population="731200"/]
      [city name="Rotterdam" district="Zuid-Holland" population="593321"/]
      [city name="Haag" district="Zuid-Holland" population="440900"/]
      [city name="Utrecht" district="Utrecht" population="234323"/]
      [city name="Eindhoven" district="Noord-Brabant" population="201843"/]
    [/cities]
  [/country]
  ...
[/countries]
        


走到这一步,生成新的 XSL 样式表说明新 XML 结构就很容易了:


清单 10. 转换清单 9 的 XSL 样式表
               
[?xml version="1.0" encoding="UTF-8"?]
[xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"]
    [xsl:template match="/countries"]
        [html]
            [head]
                [style type="text/css"]
                td { text-align: center; padding: 3px; }
                .head { font-style: italic; }
                [/style]
            [/head]
            [body]
                [xsl:for-each select="country"]
                    [h2][xsl:value-of select="@name"/] - [xsl:value-of
                    select="@continent"/][/h2]
                    [table border="1"]
                        [thead]
                            [tr]
                                [xsl:for-each select="cities/city[1]/@*"]
                                [td class="head"]
                                    [xsl:value-of select="name(.)"/]
                                [/td]
                                [/xsl:for-each]
                            [/tr]
                        [/thead]
                        [tbody]
                            [xsl:apply-templates/]
                        [/tbody]
                    [/table]
                [/xsl:for-each]
            [/body]
        [/html]
    [/xsl:template]

    [xsl:template match="cities/city"]
      [tr]
        [xsl:for-each select="@*"]
        [td]
            [xsl:value-of select="."/]
        [/td]
        [/xsl:for-each]
    [/tr]
    [/xsl:template]
[/xsl:stylesheet]
        


当然,您接下来也可以修改原始的 PHP 脚本以使用此样式表转换生成的 XML。但是,改动很小:

 

清单 11. 转换清单 8 生成的 XML 输出
               
[?php
// include required files
include 'XML/Query2XML.php';
include 'MDB2.php';

try {
    // initalize Query2XML object
    $q2x = XML_Query2XML::factory(MDB2::factory('mysql://root:pass@localhost/world'));
   
    // generate SQL query
    // get results as XML
    $sql_1 = "SELECT * FROM Country";
    $sql_2 = "SELECT * FROM City WHERE CountryCode = ? ORDER BY Population DESC LIMIT 5";
    $xml = $q2x-]getXML($sql_1, array(
            'idColumn' =] 'code',
            'rootTag' =] 'countries',
            'rowTag' =] 'country',
            'attributes' =] array('code', 'name', 'continent'),
            'elements' =] array('cities' =] array(
                'sql' =] array('data' =] array('code'), 'query' =] $sql_2),
                'idColumn' =] 'id',
                'rootTag' =] 'cities',
                'rowTag' =] 'city',
                'attributes' =] array('name','district','population'))
            )
        )   
    );
   
    // read XSL stylesheet data
    $xsl = new DOMDocument;
    $xsl-]load('countries.xsl');
   
    // initialize XSLT engine
    $xslp = new XSLTProcessor;
   
    // attach XSL stylesheet object
    $xslp-]importStyleSheet($xsl);
   
    // perform transformation
    header('Content-Type: text/html');
    echo $xslp-]transformToXML($xml);
} catch (Exception $e) {
    echo $e-]getMessage();
}
?]
        


图 2 显示了转换后的 XML 的外观:

 


图 2. 由清单 11 生成的 HTML 文档
XSL 转换后生成的 HTML 页面

 

您可以以多种方式使用这种嵌套功能,并且 XML_Query2XML 也提供了各种选项以进一步调整 XML 输出。您可以在 XML_Query2XML 手册中找到详细示例(参阅 参考资料)。

 

 


 回页首
 

 

使用 XPath 过滤 SQL 记录

您可以想像,约束 getXML() 方法的输出,使其匹配某些约束条件非常容易。只需将合适的 WHERE 子句添加到 SQL 查询中即可。另外也可以使用 XPath 构造创建 XML 节点树的过滤子集并将其返回给调用方。

在清单 12 中,查看一个实现此功能的简单示例,修改 清单 11 并约束输出 XML 以便只列出欧洲的国家和城市,使用了一个 XPath 条件:


清单 12. 使用 XPath 约束 SQL-to-XML 输出
               
[?php
// include required files
include 'XML/Query2XML.php';
include 'MDB2.php';

try {
    // initialize Query2XML object
    $q2x = XML_Query2XML::factory(MDB2::factory('mysql://root:pass@localhost/world'));
   
    // generate SQL query
    // get results as XML
    $sql_1 = "SELECT * FROM Country";
    $sql_2 = "SELECT * FROM City WHERE CountryCode = ? ORDER BY Population DESC LIMIT 5";
    $xml = $q2x-]getXML($sql_1, array(
            'idColumn' =] 'code',
            'rootTag' =] 'countries',
            'rowTag' =] 'country',
            'attributes' =] array('code', 'name', 'continent'),
            'elements' =] array('cities' =] array(
                'sql' =] array('data' =] array('code'), 'query' =] $sql_2),
                'idColumn' =] 'id',
                'rootTag' =] 'cities',
                'rowTag' =] 'city',
                'attributes' =] array('name','district','population'))
            )
        )   
    );

    // now, further filter the XML using XPath
    // return only those [country] nodes which have the attribute 'continent=Europe'   
    // as a DOMNodeList
    $xpath = new DOMXPath($xml);
    $nodelist = $xpath-]query("/countries/country[@continent='Europe']");
   
    // generate a new DOM tree using the XPath result set
    // create the root element
    // import each node from the node list and append to the new DOM tree
    $dom = new DOMDocument;
    $root = $dom-]createElement('countries');
    $dom-]appendChild($root);
    $x = 0;
    while ($node = $nodelist-]item($x)) {
        $node = $dom-]importNode($node, true);
        $root-]appendChild($node);
        $x++;
    }
   
    // print XML
    header('Content-Type: text/xml');
    $dom-]formatOutput = true;
    echo $dom-]saveXML();
} catch (Exception $e) {
    echo $e-]getMessage();
}
?]
        


这段脚本的第一小段跟以前一样 — 两个嵌套的 SQL 查询,内部查询使用外部查询的数据生成一个国家和城市数据列表。但是此时,并没有立即打印 XML 或将其传递给 XSLT 处理器,而是初始化了 DOMXPath 对象,并从原始的 XML 树创建了一个新的 DOMNodeList。此 DOMNodeList 使用 XPath 查询以确保它只包含 continent 属性的值为 Europe 的 [country] 元素。一旦创建 DOMNodeList 之后,就会初始化新的 DOMDocument 并将此 DOMNodeList 一个节点接一个节点地导入其中,生成一个新的 XML 文档。

清单 13 给出了输出的一个片段:


清单 13. 由清单 12 生成的 XML 输出(经过了简化)
               
[?xml version="1.0"?]
[countries]
  [country code="NLD" name="Netherlands" continent="Europe"]
    [cities]
      [city name="Amsterdam" district="Noord-Holland" population="731200"/]
      [city name="Rotterdam" district="Zuid-Holland" population="593321"/]
      [city name="Haag" district="Zuid-Holland" population="440900"/]
      [city name="Utrecht" district="Utrecht" population="234323"/]
      [city name="Eindhoven" district="Noord-Brabant" population="201843"/]
    [/cities]
  [/country]
  [country code="ALB" name="Albania" continent="Europe"]
    [cities]
      [city name="Tirana" district="Tirana" population="270000"/]
    [/cities]
  [/country]
  [country code="AND" name="Andorra" continent="Europe"]
    [cities]
      [city name="Andorra la Vella" district="Andorra la Vella" population="21189"/]
    [/cities]
  [/country]
  [country code="BEL" name="Belgium" continent="Europe"]
    [cities]
      [city name="Antwerpen" district="Antwerpen" population="446525"/]
      [city name="Gent" district="East Flanderi" population="224180"/]
      [city name="Charleroi" district="Hainaut" population="200827"/]
      [city name="Liège" district="Liège" population="185639"/]
      [city name="Bruxelles [Brussel]" district="Bryssel" population="133859"/]
    [/cities]
  [/country]
  ...
[countries]
        

 

 


 回页首
 

 

合并来自多个源的数据

在基于 XML 的应用程序的实际开发中,XML 文档中保存的信息不太可能来自一个源。除了一个或多个 SQL 结果集外,它还可能包含来自磁盘文件的数据、来自外部 Web 服务的数据,以及来自系统进程表的数据。为了应对这些情形,XML_Query2XML 提供了一种方法,用于将来自非 SQL 源的数据集成到 getXML() 方法返回的 XML 中。

XML_Query2XML 允许开发人员定义定制的回调函数,由输出 XML 中的特定元素调用。这些回调函数将在内部获得所需的数据,将其转换为 XML,并将此 XML(像 DOMNode 实例一样)返回给调用方,适合于在 XML 文档树中合适的位置插入。这些回调函数必须跟在 getXML() 调用中的散列(#)符号之后,并将自动接收当前 SQL 记录作为输入。

您也许会问这是否真的有用。这个问题最好用示例回答。首先,假设您希望生成一个 XML 文档,其中列出一些国家及其人口最多的城市。您前面见过的许多示例都可以实现这个功能。为了让示例变得更有趣些,我们对此 XML 进行增强,使用 GeoNames Web 服务的数据给 XML 附上每个指定城市的经纬度。

清单 14 给出了代码:


清单 14. 将 Web 服务数据与 SQL-to-XML 输出集成
               
[?php
ini_set('max_execution_time', 120);
// include required files
include 'XML/Query2XML.php';
include 'MDB2.php';

try {
    // initalize Query2XML object
    $q2x = XML_Query2XML::factory(MDB2::factory('mysql://root:pass@localhost/world'));
   
    // generate SQL query
    // get results as XML
    $sql = "SELECT Country.Code2 AS code, Country.Name AS country, City.Name AS city,
        City.Population AS population FROM Country, City
        WHERE Country.Code = City.CountryCode GROUP BY City.CountryCode
        HAVING City.Population = MAX(City.Population) ORDER BY City.Population
        DESC LIMIT 15";
    $xml = $q2x-]getXML($sql, array(
            'idColumn' =] 'code',
            'rootTag' =] 'countries',
            'rowTag' =] 'country',
            'attributes' =] array('code', 'name' =] 'country'),
            'elements' =] array('city' =] array (
                'elements' =] array(
                    'name' =] 'city',
                    'population',
                    'location' =] '#getLocation'),
                )
            ),
        )   
    );
   
    // print XML
    header('Content-Type: text/html');
    $xml-]formatOutput = true;
    print $xml-]saveXML();
} catch (Exception $e) {
    echo $e-]getMessage();
}

// function to get data from GeoNames Web service
// call GeoNames with country code and city name
// create XML document fragment with returned values
function getLocation($record) {
    // get data and format into SimpleXML object
    $sxml = simplexml_load_string(file_get_contents(
        "http://ws.geonames.org/search?maxRows=1&name=" .
            urlencode(utf8_encode($record['city'])) . "&country=" .
            urlencode(utf8_encode($record['code']))));
   
    // extract data from SimpleXML object
    // convert into DOMNode fragments
    $dom = new DOMDocument();
    // generate [lat] node
    $lat = $dom-]createElement('lat');
    $lat-]appendChild($dom-]createTextNode($sxml-]geoname{0}-]lat));
    // generate [long] node
    $long = $dom-]createElement('long');
    $long-]appendChild($dom-]createTextNode($sxml-]geoname{0}-]lng));
    return array($lat, $long);
}
?]
        


在 清单 14 中,对 getXML() 的调用执行 SELECT 查询,该查询将各个城市按其国家代码分组,然后选择一个人口数量最多的城市。此数据然后被转换为下面的 XML 文档(清单 15):


清单 15. 由清单 14 生成的第一阶段 XML 输出(经过了简化)
               
[?xml version="1.0" encoding="UTF-8"?]
[countries]
  [country code="AW" name="Aruba"]
    [city]
      [name]Oranjestad[/name]
      [population]29034[/population]
    [/city]
  [/country]
  ...
[/countries]
        


下一个任务是获取每个城市的经纬度并将其插入到上面的文档树中(参见 清单 14)。此信息来自 GeoNames Web 服务,可以通过 REST 访问此服务,并公开一个 search() 方法,用于返回指定位置的地理信息。对 Web 服务进行完整描述超出了本文的范围,但是您可以在本文参考资料部分阅读更多信息。

清单 16 显示了一个查询 'Berlin, Germany' 时的 GeoNames 响应包示例:


清单 16. 一个 GeoNames 响应包示例
               
[?xml version="1.0" encoding="UTF-8" standalone="no"?]
[geonames]
 [totalResultsCount]807[/totalResultsCount]
 [geoname]
  [name]Berlin[/name]
  [lat]52.5166667[/lat]
  [lng]13.4[/lng]
  [geonameId]2950159[/geonameId]
  [countryCode]DE[/countryCode]
  [countryName]Germany[/countryName]
  [fcl]P[/fcl]
  [fcode]PPLC[/fcode]
 [/geoname]
[/geonames]
        


正如您所看到的,这个响应包包含了关于指定位置的各种信息,包括我们最为关心的:经纬度。

现在,仔细查看 清单 13 中的 getXML() 调用。注意,选项数组的 location 键并没有链接到查询结果集中的字段,而是链接到了回调函数 getLocation()。这意味着每次 getXML() 处理来自 SQL 结果集的记录时,它将同一条记录作为字段-值对的关联数组传递给 getLocation() 回调函数。getLocation() 方法反过来使用 REST 调用 GeoNames Web 服务的 search() 方法,将来自 SQL 记录的城市和国家名称作为参数传递给它,并作为 SimpleXML 对象搜索响应。SimpleXML 表示法然后可用于在响应包中寻找 [lat] 和 [lng] 元素,将它们转换为两个单独的 DOMNode 实例,并将它们传回 getXML() 作为数组插入树中。

最后,清单 17 给出了输出 XML 的外观:


清单 17. 由清单 14 生成的最终 XML 输出(经过了简化)
               
[?xml version="1.0" encoding="UTF-8"?]
[countries]
  [country code="IN" name="India"]
    [city]
      [name]Mumbai (Bombay)[/name]
      [population]10500000[/population]
      [location]
        [lat]18.975[/lat]
        [long]72.8258333[/long]
      [/location]
    [/city]
  [/country]
  [country code="KR" name="South Korea"]
    [city]
      [name]Seoul[/name]
      [population]9981619[/population]
      [location]
        [lat]37.5663889[/lat]
        [long]126.9997222[/long]
      [/location]
    [/city]
  [/country]
  ...
[/countries]
        


正如此示例所阐明那样,使用定制的回调函数是一种将其他源的数据提取到 getXML() 生成的 XML 输出中的简单方法。清单 14 连接到外部 Web 服务;您可以同样轻松地将外部文件或 XML-RPC 调用的输出导入到最终的 XML 树中。

 

 


 回页首
 

 

创建数据库备份

XML_Query2XML 的另外一个有用的应用是将数据库表的内容转储为基于 XML 的格式,用于存储和备份目的。这类备份脚本背后的逻辑很简单:从数据库取得一个表列表,迭代此列表并使用如 DESC ? 和 SELECT * FROM ? SQL 之类的命令分别提取每个表的模式和记录。如果您跟随本文的思路,可能已经想到需要使用 getXML() 方法调用以完成此任务。

执行此任务比最初预想的要困难一些,主要是由于 MDB2 抽象层有一些限制:即,在准备好的查询中不能处理列和表名的占位符。这让使用之前提到的 DESC ? 和 SELECT * FROM ? 查询非常困难,因为 MDB2 层在遇到此类查询时将只是生成错误。

那该怎么办?发挥一点创造力,如清单 18 所示:


清单 18. 生成数据库结构和内容的 XML 清单
               
[?php
ini_set('max_execution_time', 120);

// include required files
include 'XML/Query2XML.php';
include 'MDB2.php';

// set database name
$db = 'world';

try {
    // initialize Query2XML object
    $q2x = XML_Query2XML::factory(MDB2::factory('mysql://root:pass@localhost/' . $db));

    // SQL query to get table list
    // note: this SQL query varies from database to database
    $sql = "SHOW TABLES";
    $xml = $q2x-]getXML($sql, array(
                'idColumn' =] false,
                'rootTag' =] 'database',
                'rowTag' =] 'table',
                'attributes' =] array('name' =] 'tables_in_' . $db))   
    );

    // get a list of all the [table] nodes
    $nodelist = $xml-]getElementsByTagName("table");   
   
    // iterate over the nodes
    $x = 0;
    while ($node = $nodelist-]item($x)) {
        // extract the table name
        $table = $node-]attributes-]getNamedItem('name')-]nodeValue;
       
        // get table description
        // as DOM document
        // note: this SQL query varies from database to database
        $sql_1 = 'DESC ' . $table;
        $schema = $q2x-]getXML($sql_1, array (
            'idColumn' =] 'field',
            'rowTag' =] 'define',
            'rootTag' =] 'schema',
            'elements' =] array('*'))
        );
       
        // get table contents
        // as another DOM document
        $sql_2 = 'SELECT * FROM ' . $table;
        $data = $q2x-]getXML($sql_2, array (
            'idColumn' =] false,
            'rowTag' =] 'record',
            'rootTag' =] 'data',
            'elements' =] array('*'))
        );
       
        // iterate over the $schema DOM document
        // use XPath to get the [schema] node and all its children
        // import it into the main XML tree, under the corresponding [table] element
        // credit: Igor Kraus, http://www.php.net/simplexml for this suggestion
        $xpath = new DOMXPath($schema);
        $query = $xpath-]query('//schema');
        for ($i = 0; $i [ $query-]length; $i++) {
            $xml-]documentElement-]childNodes-]item($x)-]appendChild(
                $xml-]importNode($query-]item($i), true));
        }
       
        // do the same for the $data DOM document
        $xpath = new DOMXPath($data);
        $query = $xpath-]query('//data');
        for ($i = 0; $i [ $query-]length; $i++) {
            $xml-]documentElement-]childNodes-]item($x)-]appendChild(
                $xml-]importNode($query-]item($i), true));
        }
       
        // increment counter for the next run
        $x++;
    }
   
    // write output to disk
    // print success/error message
    $xml-]formatOutput = true;
    if ($xml-]save('/tmp/dump.xml')) {
        echo 'Data successfully saved!';
  

评论

相关推荐

    将sql数据转化为xml格式说明

    ### 将 SQL 数据转换为 XML 格式说明 在当今数据处理领域,数据格式的转换是一项常见的需求。本文档详细介绍了如何将从 SQL 数据库获取的数据转换为 XML 格式,这对于希望集成不同系统或进行数据交换的开发人员来说...

    php xml转数组

    这里,`simplexml_load_string`函数将XML字符串转换为一个SimpleXMLElement对象,然后通过将其转换为JSON字符串,再反序列化回PHP数组,从而实现转换。 在我们的压缩包文件中,有一个名为`xml.class.php`的文件,...

    Xml2Mysql:获取一个mysqldump xml文件并将其转换为与MySQL兼容SQL文件

    一个非常粗糙的未经测试的库,用于使用PHP将mysqldump XML导出转换为SQL。 用法示例 从mysqldump.xml生成SQL并回显结果 $ dumpParser = new Initvector \ Xml2Mysql \ DumpParser (); $ dumpParser -> generateSql...

    php+xml php+ajax php+mysql

    例如,使用SimpleXML库可以方便地将XML数据转换为PHP对象,便于操作。同时,PHP也可以生成XML响应,为前端提供结构化数据。 **AJAX(Asynchronous JavaScript and XML)** AJAX不是一种单一的技术,而是一种利用...

    xml 中连接数据库的方法

    - 使用`fetchall()`或`fetchone()`获取结果,将其转换为XML格式。 3. **PHP + PDO (PHP Data Objects)** - PHP的PDO扩展提供了一种统一的方式来访问多种数据库。 - 使用`new PDO()`构造函数,传入DSN(数据源...

    将数据库数据以XML文件格式保存

    3. **转换数据**: 使用数据库提供的功能或编程语言(如Python、Java、PHP)的库将查询结果转换为XML。例如,SQL Server有`FOR XML`子句,MySQL有`XML CONCAT`函数,而Python有`xml.etree.ElementTree`模块。 4. **...

    使用PHP和AJAX的XML编程

    DB2提供了对XML的索引、查询、转换等高级功能,结合SQL/XML和XQuery,可以处理和检索XML数据。 【Ajax与PHP】在Web开发中,JavaScript通过Ajax可以调用PHP脚本,从而实现客户端与服务器之间的通信。PHP脚本处理接收...

    数据库与xml的导入导出

    可以使用`XMLType`对象的`getClob()`方法将XML数据转换为CLOB,然后插入到支持CLOB类型的列。或者使用`INSERT INTO ... VALUES (XMLType('<xml>'))`直接插入XML数据。 三、MySQL中的XML导入导出 1. 导出XML:MySQL...

    php_sql.zip_Known_c php post_json文件转换_php 数组 转 sql

    将数组,HTML,XML或JSON文件转换为SQL语法。 使用 ======================== - SELECT *FROM myArray ORDER BY key DESC,value ASC, - SELECT key,value FROM myArray WHERE value= 100 , - SELECT * FROM json_...

    php加载和生成json和生成xml文件,并带有ajax分页效果,带图带数据库

    在PHP生成JSON时,首先需要创建一个数组或对象,然后使用`json_encode()`将其转换为JSON字符串。例如: ```php $data = array('name' => 'John', 'age' => 30); $json = json_encode($data); echo $json; // 输出:...

    php从数据库中读取数据生成xml

    该脚本展示了如何使用PHP从MySQL数据库中读取数据,并将这些数据转换成XML格式。需要注意的是,所使用的`mysql_`函数已经废弃,建议使用更现代的方法如`mysqli_`系列函数或PDO扩展来实现相同的功能,以确保代码的...

    讲XML中的数据写入网页实例

    XSLT是一种样式表语言,用于转换XML文档。通过XSLT,我们可以定义如何将XML数据转换为HTML,以在浏览器中显示。 以下是一个简单的例子,展示了如何用XML和XSLT将数据呈现到网页上: 1. 首先,创建一个XML文件(如`...

    数据库数据生成xml

    4. **数据转换**:使用编程语言的XML库(如Java的DOM、SAX或StAX,Python的lxml,PHP的DOMDocument)将查询结果转换为XML文档。可以手动构建XML树,或者使用库提供的方法自动转换。 5. **XML格式化**:为了确保XML...

    数据库转为XML格式

    3. 数据转换:使用编程语言(如Python、Java、PHP等)的库或工具(如XSLT)将查询结果转化为XML格式。XSLT(Extensible Stylesheet Language Transformations)是一种专门用于转换XML的样式表语言。 4. 格式化:确保...

    PHP ajax XML 获取省份地区邮政编码信息

    在本案例中,PHP负责从MySQL数据库中查询省份和邮政编码数据,并将结果转换为XML格式。 2. AJAX(Asynchronous JavaScript and XML):AJAX允许Web页面在不刷新整个页面的情况下,与服务器进行数据交互。它通过...

    Oracle XML开发手册

    它将XML文档直接存储在数据库中,而不是将其转换为关系表格,从而保持了XML的原始结构和语义。XMLDB提供了强大的查询能力,包括XPath和XQuery,使得开发者可以直接对XML数据进行操作。 2. **BINARY XML**:Oracle...

    php实现解析xml并生成sql语句的方法

    解析XML,获取所有的节点属性 –> 循环节点集合,获取对应的属性 –> 拼接sql字符串存入一数组 –> 将数组转为字符串保存于某一文件中 这里使用了xpath,在写代码的过程中遇到两个问题: 1、xml的史路径属性为D:\xx\...

    php中处理xml

    XSLT(Extensible Stylesheet Language Transformations)是一种用于转换XML文档的编程语言。它可以将一种格式的XML文档转换为另一种格式,甚至可以转换为非XML格式如HTML或PDF。XSLT的关键特性包括: - **强大的...

    全世界的城市数据表sql脚本

    PHP代码读取这个XML文件并可能将其转换为SQL语句,以便将数据导入到SQL数据库中。 标签“sql脚本”和“城市”表明了文件的主要内容是与SQL操作和地理信息相关。这可能涉及到城市名的存储、查询优化、数据清洗等方面...

    PHP实现数组array转换成xml的方法

    这个例子展示了如何使用PHP将复杂的数据结构转换成XML,这在数据交换或API接口中非常有用。同时,这个方法也体现了PHP处理数组和XML转换的灵活性。对于PHP开发者来说,理解这种转换技巧是非常重要的,因为XML是一种...

Global site tag (gtag.js) - Google Analytics