关键词:
在传递数据时,XML和JSON是最常用的数据格式,SQL Server从很早的版本就开始支持XML格式,而对于JSON格式,SQL Server从2016版本开始支持。大多数数据库系统并没有升级到SQL Server 2016版本,因此在传递格式化的数据时,通常还是使用XML格式。对我而言,查询和解析XML格式的数据需要掌握的知识点较多,MSDN上关于XML的文档,又试图把XML的各个方面都讲解地清清楚楚,以至于内容冗杂,使学习过程变得困难。我十分不喜欢学习这些不常用的数据结构,再说,在平时的数据库开发中,用到XML的地方也很少,可是,一旦在应用程序中用到XML,就只有头疼的份了,既然避不开XML,那就用最简单的方法学习它,了解它,使用它,以备不时之需。写这篇文章,就是以最简单的方式,分享XML最常用的使用方法。
一,XML数据格式的简单介绍
1,最简单的XML格式
XML数据最简单的格式是:
- 开始标签:<tag>
- 标签的属性,属性值用双引号:<tag id="1" name="azure">,在单个节点中,属性名不能重复,属性之间使用空格分隔,在开始标签中,才能设置属性;
- 结束标签:</tag>,结束标签不能有属性;
- 子节点:在开始标签和结束标签,可以包含节点,叫做子节点;
- 节点值:在开始标签和结束标签的标量值,叫做节点值;
2,使用字符串对XML数据赋值
数据类型XML用于存储XML格式化的文本数据,在本例中,声明一个XML类型的变量 @xml,并赋值,后文示例都使用该变量用于数据查询。
declare @xml xml set @xml=' <Expression ID="1" TaxonomyID="1"> <SubExpression ID="1" OperandType="Tag" Operator="and"> <Oprand ID="268819" Name="abuse" /> <Oprand ID="277029" Name="mongohq" /> <Oprand ID="516813" Name="access" /> </SubExpression> <SubExpression ID="2" OperandType="Tag" Operator="and"> <Oprand ID="283839" Name="reviews" /> <Oprand ID="697348" Name="retention" /> </SubExpression> <SubExpression ID="3" OperandType="Tag" Operator="not"> <Oprand ID="281556" Name="richfaces" /> <Oprand ID="2993766" Name="rgp" /> </SubExpression> </Expression>'
二,XPath路径表达式
XPath 使用路径表达式在 XML 文档中选取节点,节点是通过沿着路径选取的,XPath是查询XML数据时必备的参数。
常用的路径表达式是:
- . :选取当前节点;
- .. :选取当前节点的父节点;
- / :从根节点开始;
- // :从匹配选择的节点开始选取,而不考虑其位置;
- * :通配符,匹配任意字符,或任意节点;
- node() :匹配任意节点,跟通配符 * 功能相似;
- @PropertyName :选取属性;
在路径表达式中,跟节点的选取有关的表达式是:
- NodeName:选取指定节点名及其所有子节点;
- NodeName[N]:选取指定节点集合的第N个节点;
- NodeName[@Name]:选取当前节点中带有指定属性的节点;
三,XML数据的查询(query()函数)
@xml.query(’xpath‘)函数,参数是路径表达式,返回XML数据类型的结果,该XML是非类型化(untyped)的。
1,选取节点及其子节点
示例中,从根节点Expression开始,选取SubExpression节点及其子节点:
select @xml.query('/Expression/SubExpression')
query()函数返回的结果如下,该查询结果是非类型化的XML数据。
<SubExpression ID="1" OperandType="Tag" Operator="and"> <Oprand ID="268819" Name="abuse" /> <Oprand ID="277029" Name="mongohq" /> <Oprand ID="516813" Name="access" /> </SubExpression> <SubExpression ID="2" OperandType="Tag" Operator="and"> <Oprand ID="283839" Name="reviews" /> <Oprand ID="697348" Name="retention" /> </SubExpression> <SubExpression ID="3" OperandType="Tag" Operator="not"> <Oprand ID="281556" Name="richfaces" /> <Oprand ID="2993766" Name="rgp" /> </SubExpression>
2,选取指定节点的所有子节点集合
select @xml.query('/Expression/SubExpression/node()') select @xml.query('/Expression/SubExpression/*')
结果集是SubExpression节点下的所有子节点:
<Oprand ID="268819" Name="abuse" /> <Oprand ID="277029" Name="mongohq" /> <Oprand ID="516813" Name="access" /> <Oprand ID="283839" Name="reviews" /> <Oprand ID="697348" Name="retention" /> <Oprand ID="281556" Name="richfaces" /> <Oprand ID="2993766" Name="rgp" />
四,XML数据的查询(value()函数)
@xml.value('xpath','sql_data_type'),返回XML数据中单个属性的标量值,在使用value()函数时,xpath 参数必须指定返回的是单个值,而value()函数不会去check返回值的数量。
一般情况下,即使xml数据只有一个属性值,静态类型化(Static typing)要求,xpath表达式也必须显式指定返回单个标量值,因此,必须指定在xpath函数的末尾添加”[1]“,通常的xpath表达式是”(xpath)[1]“。
select @xml.value('(/Expression/SubExpression[1]/@ID)[1]','int') select @xml.value('(/Expression/SubExpression/@ID)[1]','int')
五,XML数据的查询(nodes()函数)
@xml.nodes ('xpath') 函数返回节点的集合,用于把XML数据转换为关系数据表,返回的每一个行都是XML数据类型,语法是:
nodes ('xpath') as table(column)
通过nodes()函数,返回SubExpression节点及其属性,由于单个节点中,属性名不可能重复,因此,在nodes()函数返回的单个节点中,不需要通过xpath路由,直接获取当前节点的属性值,这样,可以在xpath表达式中直接指定属性,不需要显式以“[1]”结尾。
示例代码如下,在value()函数中,直接指定属性值,表示获取当前节点的属性值:
select t.v.query('.') as SubExpression ,t.v.value('@ID','int') as SubExpressionID ,t.v.value('@OperandType','varchar(16)') as OperandType ,t.v.value('@Operator','varchar(16)') as Operator from @xml.nodes('/Expression/SubExpression') as t(v)
通过cross apply 连接操作,把SubExpression节点下的所有数据都转换为关系型数据,并把该数据存储到临时数据表#Expressions中:
;with cte_Expressions as ( select e.v.query('.') as Expression ,e.v.value('@ID','int') as ExpressionID ,e.v.value('@TaxonomyID','int') as TaxonomyID from @xml.nodes('/Expression') as e(v) ) ,cte_SubExpression as ( select e.ExpressionID ,e.TaxonomyID ,se.SubExpression ,se.SubExpressionID ,se.OperandType ,se.Operator from cte_Expressions e cross apply ( select t.v.query('.') as SubExpression ,t.v.value('@ID','int') as SubExpressionID ,t.v.value('@OperandType','varchar(16)') as OperandType ,t.v.value('@Operator','varchar(16)') as Operator from e.Expression.nodes('/Expression/SubExpression') as t(v) ) as se ) select p.TaxonomyID ,p.ExpressionID ,p.SubExpressionID ,p.OperandType ,p.Operator ,d.OperandID ,d.OperandName from cte_SubExpression p cross apply ( select t.v.value('@ID','int') as OperandID ,t.v.value('@Name','varchar(32)') as OperandName from p.SubExpression.nodes('/SubExpression/Oprand') as t(v) ) as d
六,把行集数据转化为XML数据(for xml path)
把行集数据转化为XML数据,需要用到for xml path子句,该子句的特点是:
- path('root') 子句用于指定根节点;
- select子句的字段别名用于指定属性,别名中必须使用@符号标识出属性名,例如:'@PropertyName';
- 在select 子句中,如果不在别名中把字段指定为属性,那么该字段的值作为节点值,节点值分为标量类型和XML类型;
- 对于标量类型,节点值是标量值;
- 对于XML类型,节点值是子节点的集合;
例如,要把数据转换为如下的关系型数据结构,其SubExpression字段是一个非类型化的XML数据,要完成这样的数据转换,必须使用for xml path子句和cast()类型转换:
<SubExpression ID="1" OperandType="Tag" Operator="not"> <Oprand ID="268819" Name="abuse" /> <Oprand ID="277029" Name="mongohq" /> <Oprand ID="516813" Name="access" /> </SubExpression> <SubExpression ID="2" OperandType="Tag" Operator="not"> <Oprand ID="283839" Name="reviews" /> <Oprand ID="697348" Name="retention" /> </SubExpression> <SubExpression ID="3" OperandType="Tag" Operator="not"> <Oprand ID="281556" Name="richfaces" /> <Oprand ID="2993766" Name="rgp" /> </SubExpression>
使用类型转换的目的,是为了把for xml path返回的字符串转换成XML数据类型,这样,就能以XML格式嵌入到上次的for xml path的结构中,作为子节点:
;with cte_Expressions as
(
select distinct ExpressionID
,TaxonomyID
from #Expressions with(nolock)
)
,cte_SubExpressions as
(
select o.ExpressionID
,o.SubExpressionID
,o.OperandType
,o.Operator
from #Expressions o with(nolock)
group by o.ExpressionID
,o.SubExpressionID
,operandType
,o.Operator
)
select e.TaxonomyID as TaxonomyID
,e.ExpressionID as ExpressionID
,cast(
(
select o.SubExpressionID as '@ID'
,o.OperandType as '@OperandType'
,case o.Operator when '&' then 'and' else 'not' end as '@Operator'
,cast((
select op.OperandID as '@ID'
,op.OperandName as '@Name'
from #Expressions op with(nolock)
where o.ExpressionID=op.ExpressionID
and o.SubExpressionID=op.SubExpressionID
for xml path('Oprand')
)as xml)
from cte_SubExpressions o
where o.ExpressionID=e.ExpressionID
for xml path('SubExpression')
) as xml)
as SubExpressions
from cte_Expressions e
还有两个函数modify()和exist(),用于XML数据的修改和检查,由于在我当前接触的项目中,没有用到过,我就不写了。
到此,文章也该结尾了,XML的极简用法已经总结了很多,在以后工作中国,如果用到XML时,翻开这篇文章,能够快速解决XML常见的数据查询和解析问题,这样就足够了。
参考文档:
Maven pom.xml 中将 log4j2 的所有用法升级到 2.15.0 的最简单方法是啥,包括使用 log4j2 的依赖项?请参阅 CVE-2021-44228
】Mavenpom.xml中将log4j2的所有用法升级到2.15.0的最简单方法是啥,包括使用log4j2的依赖项?请参阅CVE-2021-44228【英文标题】:WhatistheeasiestwayinMavenpom.xmltoupgradeallusagesoflog4j2to2.15.0,includingdependenciesusinglog4j2?SeeCVE-2021-44228Mavenpom.xml中将log... 查看详情
java使用logback发送日志到控制台文件elk的最简单用法
一、简述 本文讲JAVA使用Logback发送日志到控制台、文件、ELK的最简单用法。 二、教程 1、新建pom.xml项目引入下列依赖:<dependencies><!--BeginLogBackLog--><!--https://mvnrepository.com/artifact/ch.qos.logback/logback-classic--&g 查看详情
python中yield的用法详解——最简单,最清晰的解释(代码片段)
首先,如果你还没有对yield有个初步分认识,那么你先把yield看做“return”,这个是直观的,它首先是个return,普通的return是什么意思,就是在程序中返回某个值,返回之后程序就不再往下运行了。看做return之后再把它看做一个... 查看详情
Java:将 XML 导入数据库,最简单的方法是啥?
】Java:将XML导入数据库,最简单的方法是啥?【英文标题】:Java:XMLintoaDatabase,whatsthesimplestway?Java:将XML导入数据库,最简单的方法是什么?【发布时间】:2011-05-1323:58:56【问题描述】:我有很多XML文件,还有一个XSD。我想简单... 查看详情
从 XmlDocument 中获取带有换行符的缩进 XML 的最简单方法是啥?
】从XmlDocument中获取带有换行符的缩进XML的最简单方法是啥?【英文标题】:WhatisthesimplestwaytogetindentedXMLwithlinebreaksfromXmlDocument?从XmlDocument中获取带有换行符的缩进XML的最简单方法是什么?【发布时间】:2010-09-1705:46:41【问题描... 查看详情
从 PHP 脚本获取和解释 XML 文件响应的最简单方法是啥? [复制]
】从PHP脚本获取和解释XML文件响应的最简单方法是啥?[复制]【英文标题】:Whichistheeasiestapproachtoget&interpretaXMLfileresponsefromaPHPscript?[duplicate]从PHP脚本获取和解释XML文件响应的最简单方法是什么?[复制]【发布时间】:2012-03-3118... 查看详情
从 unix 命令行进行基本 xml 解析的最简单方法
】从unix命令行进行基本xml解析的最简单方法【英文标题】:Simplestwaytodobasicxmlparsingfromunixcommandline【发布时间】:2012-03-0107:26:04【问题描述】:我正在搜索具有某些属性的xml文件。例如,包含以下模式的文件:<param-value><na... 查看详情
将此 XML 数据转换为 JSON 格式的最简单方法 [重复]
】将此XML数据转换为JSON格式的最简单方法[重复]【英文标题】:SimplestwaytotransformthisXMLdatatoJSONformat[duplicate]【发布时间】:2021-09-1904:38:23【问题描述】:我需要使用PHP将此XML转换为正确的JSON格式,但我尝试过的任何方法似乎都不... 查看详情
在 Java 应用程序中读取 XML 文件的最佳/最简单方法是啥? [关闭]
】在Java应用程序中读取XML文件的最佳/最简单方法是啥?[关闭]【英文标题】:Whatisthebest/simplestwaytoreadinanXMLfileinJavaapplication?[closed]在Java应用程序中读取XML文件的最佳/最简单方法是什么?[关闭]【发布时间】:2010-09-3011:53:00【问... 查看详情
最简单的模块源码分析
一、常用的模块操作命令(1)lsmod(listmodule,将模块列表显示),功能是打印出当前内核中已经安装的模块列表(2)insmod(installmodule,安装模块),功能是向当前内核中去安装一个模块,用法是insmodxxx.ko(3)modinfo(moduleinformation,模块信... 查看详情
从最简单的vector中sort用法到自定义比较函数comp后对结构体排序的sort算法
sort函数在使用中非常好用,也非常简单,而且效率与冒泡或者选择排序不是一个数量级。本文就sort函数在vector中的用法分为sort函数入门用法与自定义comp比较函数比较结构体这两个最基本的功能讲讲其用法:1、sort入门:使用sor... 查看详情
python中yield的用法详解——最简单,最清晰的解释
...见了yield这个关键字,然后百度的时候,发现没有一个能简单的让我懂的,讲起来真TM的都是头头是道,什么参数,什么传递的,还口口声声说自己的教程是最简单的,最浅显易懂的,我就想问没有有考虑过读者的感受。接下来... 查看详情
Android XML 布局中 <merge> 和 <include> 用法的简单示例
】AndroidXML布局中<merge>和<include>用法的简单示例【英文标题】:Simpleexampleof<merge>and<include>usageinAndroidXML-layouts【发布时间】:2011-02-1312:44:46【问题描述】:我很好奇AndroidXML布局中的<merge>和<include&... 查看详情
request的getparameter和getattribute的常见用法总结和$(“#id“),注解最简单的使用(代码片段)
1.EL表达式 () 必须是在域对象作用范围之内的$name等价于<%=pageContext.findAttribute("name")%>等价于<%=request.getAttibute("name")%>2.jsp和EL表达式公用的内置对象PageContext经常用到的是pageContext.request. 查看详情
zip4j最简单用法
packagecom.chentao.MicroMessage.bussiness;importjava.io.File;importjava.util.ArrayList;importjava.util.Collections;importnet.lingala.zip4j.core.ZipFile;importnet.lingala.zip4j.exception.ZipException;i 查看详情
最简单的java解析xml字符串方法
引入dom4j包<dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version></dependency> 比如阿里云视频转码服务的回调通知解析,代码如下:impor 查看详情
使用 pl/sql dom 解析器解析 XML 的最简单方法
】使用pl/sqldom解析器解析XML的最简单方法【英文标题】:EasiestwaytoparseXMLusingpl/sqldomparser【发布时间】:2012-08-0217:07:11【问题描述】:我不知道如何解释,但我会尽力而为。我正在使用OracleApex,并且在我的名为“CLOBTABLE”的表中... 查看详情
js,es标准export用法记录
...utils.constant.js\'; 就可以通过constans.test调用欺骗自己最简单,欺骗自己最困难。安慰自己最简单,安慰自己最困难。 查看详情