原文:[SQLXML]FOR XML语法导出XML的易错之处

[SQLXML]FOR XML语法导出XML的易错之处

Version

Date

Creator

Description

1.0.0.1

2006-6-29

郑昀@Ultrapower

草稿

继续阅读之前,我们假设您熟悉以下知识:

n         MS SQL Server 2000

n         Sp_makewebtask

n         FOR XML 子句

如果不熟悉这些知识点,可以看下面两小节[准备工作一:FOR XML]和[准备工作二:sp_makewebtask];否则可以直接跳过。

[准备工作一:FOR XML]

关键词:      FOR XML AUTO/EXPLICIT

功能:          可以对现有的关系数据库执行 SQL 查询,以返回 XML 文档形式而不是标准行集的结果。若要直接检索结果,请使用 SELECT 语句的 FOR XML 子句,并且在 FOR XML 子句中指定下列 XML 模式之一:

l         RAW

l         AUTO

l         EXPLICIT

这些模式仅在设置它们的查询执行时有效。它们对后面执行的任何查询的结果没有影响。除了指定 XML 模式外,还可以请求 XML-Data 架构。

引申:          在实际工作中,肯定会经常遇到要自己去查询数据库然后组织一个XML文档的需求,这时候就可以直接用FOR XML语法。

举一个最简单的例子:

Sql script

Use pubs

 

SELECT TOP 2 title_id, title, type

       FROM titles FOR XML AUTO, ELEMENTS

那么,输出结果就是:

Sql result

XML_F52E2B61-18A1-11d1-B105-00805F49916B

-----------------------------------------------------------------------------------

<titles>

       <title_id>BU1032</title_id>

       <title>The Busy Executive&apos;s Database Guide</title>

       <type>business    </type>

</titles>

<titles>

       <title_id>BU1111</title_id>

       <title>Cooking with Computers: Surreptitious Balance Sheets</title>

       <type>business    </type>

</titles>

上面的例子,你自己并没有能够定义XML节点。下面用FOR XML EXPICIT就可以。

XML EXPLICIT的语法为:

[Element Tag!Tag!Attribute!Directive]

下面举一个例子:

Sql script

Use pubs

 

SELECT TOP 2

       1 AS Tag,

NULL AS Parent,

       title_id AS [titles!1!title_id],

       title AS [titles!1!title!element],

       type AS [titles!1!type]

FROM

       titles

FOR XML EXPLICIT

那么,输出结果就是:

Sql result

XML_F52E2B61-18A1-11d1-B105-00805F49916B

-----------------------------------------------------------------------------------

<titles title_id="BU1032" type="business    ">

<title>The Busy Executive&apos;s Database Guide</title>

</titles>

<titles title_id="BU1111" type="business    ">

<title>Cooking with Computers: Surreptitious Balance Sheets</title>

</titles>

可以看到,

由于“[titles!1!title_id]”,所以titles节点有一个属性就是title_id;

由于“[titles!1!title!element]”,所以titles节点有一个子节点就是title;

之所以有“<titles>”节点,是因为“FROM titles”,也就是表名。

很简单的语法。

但是如果数据量大的话,会发生什么事情呢?

比如我执行

Sql script

Use pubs

 

SELECT title_id, title, type

       FROM titles FOR XML AUTO, ELEMENTS

呢?

她还会返回一个完整的XML文档吗?

[准备工作二:sp_makewebtask]

关键词:       sp_makewebtask

功能:           创建一项生成 HTML 文档的任务,该文档包含执行过的查询返回的数据。

引申:           虽说这是一个SQL Server 2000用来根据查询结果来自动生成HTML文档的存储过程。但也还是经常被人用作输出XML文件的工具。

最简单的例子:

第一步,在C盘新建一个模板文件shippers_output_style.tpl,内容为:

template

<?xml version="1.0" encoding=”GB2312” ?>

<Shippers>

<%begindetail%>

<%insert_data_here%>

<%enddetail%>

</Shippers>

第二步,我们运行SQL语句:

Sql script

Use Northwind

GO

 

EXEC sp_makewebtask

       @outputfile = 'c:\Shippers.xml',

       @query = 'SELECT * FROM Shippers FOR XML AUTO',

       @templatefile ='c:\shippers_output_style.tpl'

第三步,文件已经生成,查看C盘的输出文件Shippers.xml如下:

Sql script

<?xml version="1.0" encoding=”GB2312”?>

<Shippers>

  <Shippers ShipperID="1" CompanyName="Speedy Express" Phone="(503) 555-9831"/>

  <Shippers ShipperID="2" CompanyName="United Package" Phone="(503) 555-3199" />

  <Shippers ShipperID="3" CompanyName="Federal Shipping" Phone="(503) 555-9931" />

</Shippers>

也就是说,对于FOR XML语句生成的XML数据流,本来需要你自己读,并且落地。现在,交给sp_makewebtask这个系统存储过程即可。

它只不过需要特殊的权限才可以运行:sys_admin。

不过,sp_makewebtask强大定制功能还是不错的,它本身就提供自动定时生成功能。

同样,提一个问题,如果数据量很大,sp_makewebtask输出的FOR XML结果会是什么样呢?它还会是一个有效的XML文件吗?

[回答前面的问题]

如果查询结果数据量大的话,你可能会对你所看到的东西觉得奇怪。

假如你是在SQL Server2000的查询分析器里执行的SQL语句,那么你可能会看到折成好几个记录返回,如下所示:

而不再是一个记录。

这时候,有一个有趣的问题,可能XML的节点名也被一劈两半,分成两个记录。

这时候,如果你是用sp_makewebtask的自动生成文件功能,那么XML文件内容到处都是断裂的节点名,从而无法正常解析。

类似于

. ...</descriptio

 

n><pubDate>2009-06-27

Description节点名就被分裂为两块,中间还换了行,当然这个换行是因为我们的模板文件的“<%insert_data_here%>

<%enddetail%>”存在换行,但是如果因此调整为“<%insert_data_here%><%enddetail%>”,那么sp_makewebtask就不认endtail了,“<%enddetail%>”会原封不动出现在XML文件中,而没有做置换。

所以,即使你调整template模板文件内容也无济于事。这时候,解析XML的程序就会报告类似“结束标记 'body' 与开始标记 'title' 不匹配”的错误。

为什么呢?因为sp_makewebtask的本身是为了生成HTML服务的,HTML可不在乎标签名断裂。

SQL Server XML - Multiple rows returned by for xml explicit》提到了这个现象,并给出了解释。

[解释]

原因只是你用了“错误”的工具。

我试验过,不管是SQL Server 2000的查询分析器的“文本显示”/“表格显示”,还是SQL Server 2005的SQL Server Management Studio,或者是存储过程,或者是SQL Server 2000的作业,都无法避免这个问题。

但是,如果用dotNET中的XMLReader对象来读,就可以。

Rob自己也说:

The sql reader returns records and the xmlreader returns one xml.  If you use the sqlreader you can concat the records and it will work but it is a waste to do it that way.

[可用的方法]

用下面的C#代码就可以保存一个完整的、没有被辟成几截的XML文件。注意,你的机器上必须安装SQL Server 2005安装盘下Servers\Setup\sqlxml4.msi,以拥有Microsoft.Data.SqlXml.DLL以及配套环境。

C# Codes

string coString = "Provider=sqloledb;data source=YourServer;user id=sa;password=;initial catalog=pubs";

SqlXmlCommand cmd = new SqlXmlCommand(coString);

XmlReader xr;

XmlDocument xDoc = new XmlDocument();

DataSet ds = new DataSet();

//Set the Root document tag

//to make sure the xml is well formed

cmd.RootTag = "Authors";

//set the clientSideXml property

cmd.ClientSideXml = true;

//call the existing strored proc

//and append the for xml nested syntax

cmd.CommandText = "exec  proc_output_authors";

//Execute the reader

xr = cmd.ExecuteXmlReader();

//load the xml document with

//the contents of the reader

xDoc.Load(xr);

//Persist the document to disk

xDoc.Save(txtXMLFilePath.Text);

那边的存储过程实际就是这样的语句:

/* Body of XML Document */

select

Author.au_fname as FirstName,

Author.au_lname as LastName,

Book.title as BookTitle,

Book.title_id as BookId

from

authors as Author

inner join

dbo.titleauthor as Titles

on

Author.au_id = Titles.au_id

inner join

dbo.titles as Book

on

Titles.title_id = Book.title_id

for

xml auto

[参考资料]

[SQLXML]FOR XML语法导出XML的易错之处的更多相关文章

  1. JAVASE02-Unit012: Unit07: XML语法 、 XML解析

    Unit07: XML语法 . XML解析 emplist.xml <?xml version="1.0" encoding="UTF-8"?> & ...

  2. XML 语法规则

    转摘自:http://www.w3school.com.cn/xml/xml_elements.asp XML 语法规则 XML 文档包含 XML 元素. XML 的语法规则很简单,且很有逻辑.这些规 ...

  3. 利用XML语法 SQL 列转行

    --行转列 固定xml语法 declare @xml xml ; set @xml=cast('<v>2</v><v>4</v><v>3&l ...

  4. XML 参考:XML基础 XML 简介

    XML 参考:XML基础 -- XML简介和用途 转:http://www.cnblogs.com/Dlonghow/archive/2009/01/22/1379799.html XML 参考:XM ...

  5. xml语法、DTD约束xml、Schema约束xml、DOM解析xml

    今日大纲 1.什么是xml.xml的作用 2.xml的语法 3.DTD约束xml 4.Schema约束xml 5.DOM解析xml 1.什么是xml.xml的作用 1.1.xml介绍 在前面学习的ht ...

  6. 【风马一族_xml】xml语法

    xml语法 文档声明 用来声明xml的属性,用来指挥解析引擎如何去解析当前xml 通常一个xml都要包含并且只能包含一个文档声明 xml的文档必须在整个xml的最前面,在文档声明之前不能有任何内容 & ...

  7. Lazarus中TreeView导出XML以及XML导入TreeView

    本来说是要给自己的某程序加一个xml导出功能,但是自己也没接触过xml,加之delphi和lazarus的xml部分还都不一样,折腾好久(整一天)才解决问题.. 如下是作为导出功能的组件部分: uni ...

  8. 使用XML的五种场合,XML基本规则,XML的术语,结构与语法

    在很多研讨会和培训班上我遇到过许多人,他们还不明白为什么要使用XML也不知道如何 在他们的应用中使用XML.一些来自诸如Gartner公司的报告建议说,商业公司不能再做 局外人了,不能对XML置之不理 ...

  9. 老李分享:导出xml报告到手机

    老李分享:导出xml报告到手机   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908821 ...

随机推荐

  1. 在SSMS里查看TDS数据包内容

    原文:在SSMS里查看TDS数据包内容 在SSMS里查看TDS数据包内容 摘抄自<SQLSERVER2012实施与管理实战指南> 要具体查看TDS数据库的内容,我们可以: 用NETWORK ...

  2. oracle查看经常使用的系统信息

    总结了查看oracle数据库的经常使用sql ,有助于分析优化出一个健壮的系统程序来. 1.当前的数据库连接数: select count(*) from v$process 2.数据库同意的最大连接 ...

  3. StackExchange.Redis Client

    StackExchange.Redis Client 这期我们来看StackExchange.Redis,这是redis 的.net客户端之一.Redis是一个开源的内存数据存储,可以用来做数据库,缓 ...

  4. 每天的学习经验:SharePoint 2013 定义自己添加的产品清单。Callout菜单项、文档关注、SharePoint服务机端对象模型查询

    前言: 前一段时间一直都比較忙.没有什么时间进行总结,刚好节前项目上线.同一时候趁着放假能够好好的对之前遇到的一些问题进行总结. 主要内容有使用SharePoint服务端对象模型进行查询.为Share ...

  5. 正确lua简单的扩展,可以加速相关C++数据。

    很早的时候,我有一件事纠结.如果,我在这里C++打开界面脚本.使用C++其中一个目标,和.我的程序有很多不同的lua虚拟机.每个虚拟机与一个关联C++对象,它是多线程,那么如何快速应利用这个好时机lu ...

  6. Eclipse build launcher 3具体步骤

    1. 下载launcher 3源代码  (需要FQ) git clone https://android.googlesource.com/platform/packages/apps/Launche ...

  7. Repository、IUnitOfWork 和 IDbContext 的实践

    Repository.IUnitOfWork 和 IDbContext 的实践 好久没写 DDD 领域驱动设计相关的文章了,嘎嘎!!! 这几天在开发一个新的项目,虽然不是基于领域驱动设计的,但我想把 ...

  8. Android.9图片评论(一个)

    什么是.9图片 至于什么是.9图片这里就简单提一下,即图片后缀名前有.9的图片,如pic.9.png.pic1.9.jgp,诸如此类的图片就称为.9图片. .9图片的作用 ①.9图片的作用是在图片拉伸 ...

  9. 博客搬到了http://xianglong.me

    自己用Django建立个人博客.这个博客的部分已经迁移到新的个人博客. 博客地址:龙 (http://xianglong.me),欢迎. 版权声明:本文博客原创文章,博客,未经同意,不得转载.

  10. Android应用程序的组成部分和Manifest文件(转)

    Android应用程序由松散耦合的组件组成,并使用应用程序Manifest绑定到一起:应用程序Manifest描述了每一组件和它们之间的交互方式,还用于指定应用程序元数据.其硬件和平台要求.外部库以及 ...