UUID 与 XML 扩展
UUID 与 XML 扩展
本文件包含模块:uuid-ossp(UUID 生成)、xml2(XPath/XSLT 查询)。
uuid-ossp
uuid-ossp模块提供函数使用几种标准算法之一产生通用唯一标识符(UUID)。还提供产生某些特殊 UUID 常量的函数。此模块仅适用于核心Halo中提供的以外的特殊要求。这个模块被认为是"可信的",也就是说,它可以由对当前数据库具有CREATE权限的非超级用户安装。
uuid-ossp 函数
表 D.32展示了可用来产生 UUID 的函数。相关标准 ITU-T Rec. X.667、ISO/IEC 9834-8:2005 以及 RFC 4122 指定了四种用于产生 UUID 的算法,分别用版本号 1、3、4、5标识(没有版本 2 的算法)。这些算法中的每一个都适合于不同的应用集合。
表 D.32. 用于 UUID 产生的函数
函数/简述:
uuid_generate_v1 () → uuid:产生一个版本 1 的 UUID。这涉及到计算机的 MAC 地址和一个时间戳。注意这UUID 会泄露产生该标识符的计算机标识以及产生的时间,因此它不适合某些对安全性很敏感的应用。uuid_generate_v1mc () → uuid:这个函数产生一个版本 1 的 UUID,但是使用一个随机广播 MAC 地址而不是该计算机真实的 MAC 地址。uuid_generate_v3 ( namespace uuid, name text ) → uuid:使用指定的输入名称在给定的名字空间中产生一个版本 3 的 UUID。该名字空间应该是由uuid_ns_*()函数(如表 F.33所示)产生的特殊常量之一(理论上它可以是任意 UUID)。名称是选择的名字空间中的一个标识符。例如: SELECT uuid_generate_v3(uuid_ns_url(), 'http://www.postgresql.org\'); 名称参数将使用 MD5 进行哈希,因此从产生的 UUID 中得不到明文。采用这种方法的 UUID 生成没有随机性并且不涉及依赖于环境的元素,因此是可以重现的。uuid_generate_v4 () → uuid:产生一个版本 4 的 UUID,它完全从随机数产生。uuid_generate_v5 ( namespace uuid, name text ) → uuid:产生一个版本 5 的 UUID,它和版本 3 的 UUID 相似,但是采用的是 SHA-1 作为哈希方法。版本 5 比版本 3 更好,因为 SHA-1 被认为比 MD5 更安全。
表 D.33. 返回 UUID 常量的函数
函数/简述:
uuid_nil () → uuid:返回一个"nil" UUID 常量,它不作为一个真正的 UUID 出现。uuid_ns_dns () → uuid:返回为 UUID 指定 DNS 名字空间的常量。uuid_ns_url () → uuid:返回为 UUID 指定 URL 名字空间的常量。uuid_ns_oid () → uuid:返回为 UUID 指定 ISO 对象标识符(OID) 名字空间的常量(这属于 ASN.1 OID,它与PostgreSQL使用的 OID 无关)。uuid_ns_x500 () → uuid:返回为 UUID 指定 X.500 可识别名(DN)名字空间的常量。
编译uuid-ossp
在历史上这个模块依赖于 OSSP UUID 库,这也是这个模块名称的由来。uuid-ossp现在在一些平台上可以脱离 OSSP 库被编译。
在 FreeBSD、NetBSD 和一些其他源自 BSD 的平台上,在核心的libc 库中已经包括了合适的 UUID 创建函数。在 Linux、macOS和一些其他平台上, libuuid库中提供了合适的函数,它最初是来自于 e2fsprogs项目(不过在现代 Linux 上它被认为是 util-linux-ng的一部分)。在调用configure时, 指定--with-uuid=bsd可使用 BSD 的函数,指定 --withuuid=e2fs会使用e2fsprogs的 libuuid,指定--with-uuid=ossp则会 使用 OSSP UUID 库。
在一台特定的机器上可能会存在多种上述的库,因此 configure不会自动选择其中一个。
xml2
xml2模块提供 XPath 查询和 XSLT 功能。
函数的描述
表 D.34展示了这个模块提供的函数。这些函数提供了直接的 XML 解析和 XPath 查询。
表 D.34. xml2 函数
函数/描述:
xml_valid ( document text ) → boolean:解析给定的文档,如果文档是格式良好的 XML,则返回 true。xpath_string ( document text, query text ) → text:在提供的文档上评估 XPath 查询,并将结果转换为text。xpath_number ( document text, query text ) → real:在提供的文档上评估 XPath 查询,并将结果转换为real。xpath_bool ( document text, query text ) → boolean:在提供的文档上评估 XPath 查询,并将结果转换为boolean。- `xpath_nodeset (:
document text:,query text:,toptag text:,itemtag text:) → text`:这个函数在文档上计算查询并且把结果包装在 XML 标签中。如果结果是多值的,输出看起来是这样: <toptag> <itemtag>Value 1 which could be an XML fragment</itemtag> <itemtag>Value 2....</itemtag> </toptag> 如果toptag或者itemtag是一个空字符串,相关的标签会被忽略。xpath_nodeset ( document text, query text, itemtag text ) → text:类似于xpath_nodeset(document, query, toptag, itemtag)但结果省略 了toptag。xpath_nodeset ( document text, query text ) → text:与xpath_nodeset(document, query, toptag, itemtag)相似但是结果忽略两种标签。xpath_list ( document text, query text, separator text ) → text:评估文档上的查询并返回由指定分隔符分隔的多个值,例如Value 1,Value 2,Value 3,如果separator 是,.xpath_list ( document text, query text ) → text:这是上述函数的包装器,使用,作为分隔符。
xpath_table
xpath_table(text key, text document, text relation, text xpaths, text criteria) returns setof record
xpath_table是一个表函数,它在一组文档中的每一个上计算一组 XPath 查询,并且将结果作为一个表返回。来自原始文档表的主键域被返回为结果的第一列,这样结果集可以被用于连接。其参数在表 D.35中描述。
表 D.35. xpath_table 参数
--------------------------------- ------------------------------------------------------------------------------------------------------------------
参数 描述
key "key"域的名称 --- 这只是被用作输出表中第一列的域,即它标识每一个输出行是来自于哪个记录(见下面有关多个值的注解)
document 包含 XML 文档的域的名称
relation 包含文档的表或视图的名称
xpaths 一个或多个 XPath 表达式,用\|分隔
criteria WHERE 子句的内容。这不能被忽略,因此如果你想要处理关系中的所有行,可以使用true或1=1
--------------------------------- ------------------------------------------------------------------------------------------------------------------
这些参数(除了 XPath 字符串)只是会被替换到一个纯粹的 SQL SELECT 语句中,因此你有一些灵活性 --- 该语句是
SELECT <key>, <document> FROM <relation> WHERE <criteria>
因此那些参数可以是那些特定位置上合法的任何东西。来自于这个 SELECT 的结果需要返回正好两列(它确实会这样,除非你尝试为键或文档列出多个域)。注意这种简单方法要求你验证任何用户提供的值来避免 SQL 注入攻击。
该函数必须被使用在一个FROM表达式中,并带有一个AS子句来指定输出列,例如
SELECT * FROM
xpath_table('article_id',
'article_xml',
'articles',
'/article/author|/article/pages|/article/title',
'date_entered > ''2003-01-01'' ')
AS t(article_id integer, author text, page_count integer, title text);
AS子句定义了输出表中列的名称和类型。第一个是"key"域并且剩下的对应于 XPath 查询。如果 XPath 查询比结果列多,额外的查询将被忽略。如果结果列比 XPath 查询多,额外的列将是 NULL。
注意:这个例子定义page_count结果列为一个整数。该函数在内部处理字符串表达,因此当你在输出中想要一个整数时,它将采用 XPath 结果的字符串表达并且输入函数来把它转换成一个整数(或者AS子句要求的任何类型)。如果它无法做到这一点将会导致一个错误 --- 例如结果是空 --- 因此如果你认为你的数据有任何问题,你可能希望坚持用text作为列类型。
调用的SELECT语句不必只是 SELECT * --- 它可以用名称引用输出列或者将它们连接到其他表。该函数会产生一个虚拟表,你可以在其上执行任何所需的操作(例如聚集、连接、排序等)。因此我们也可以有:
SELECT t.title, p.fullname, p.email
FROM xpath_table('article_id', 'article_xml', 'articles',
'/article/title|/article/author/@id',
'xpath_string(article_xml,''/article/@date'') > ''2003-03-20''
')
AS t(article_id integer, title text, author_id integer),
tblPeopleInfo AS p
WHERE t.author_id = p.person_id;
作为一个更复杂的例子。当然,为了便利你也可以把所有这些包装在一个视图中。
D.45.3.1. 多值结果
xpath_table函数假定每一个 XPath 查询的结果可能是多值的,因此该函数返回的行数可能与输入文档的数目不同。被返回的第一行包含来自每一个查询的第一个结果,第二行则是来自每一个查询的第二个结果。如果其中一个查询的值比其他查询少,则会为它返回空值。
在某些情况下,一个用户将知道一个给定的 XPath 查询将只返回一个单一结果(可能是一个唯一文档标识符) --- 如果和一个返回多值的 XPath 查询一起使用,单值结果将只出现在结果的第一行中。对于这种情况的解决方案是使用键域作为针对一个更简单 XPath 查询的连接的一部分。一个例子:
test=# CREATE TABLE test (
test(# id int PRIMARY KEY,
test(# xml text
test(# );
CREATE TABLE
test=# INSERT INTO test VALUES (1, '<doc num="C1">
test'# <line num="L1"><a>1</a><b>2</b><c>3</c></line>
test'# <line num="L2"><a>11</a><b>22</b><c>33</c></line>
test'# </doc>');
INSERT 0 1
test=# INSERT INTO test VALUES (2, '<doc num="C2">
<line num="L1"><a>111</a><b>222</b><c>333</c></line>
<line num="L2"><a>111</a><b>222</b><c>333</c></line>
</doc>');
INSERT 0 1
test=# SELECT * FROM
xpath_table('id','xml','test','/doc/@num|/doc/line/@num|/doc/line/a|/doc/line/b|/doc/line/c','true')
test-# AS t(id int, doc_num varchar(10), line_num varchar(10), val1 int, val2 int,val3 int)
test-# WHERE id = 1 ORDER BY doc_num, line_num ;
id | doc_num | line_num | val1 | val2 | val3
----+---------+----------+------+------+------
1 | C1 | L1 | 1 | 2 | 3
1 | | L2 | 11 | 22 | 33
(2 rows)
要在每一行上得到doc_num,解决方案是使用xpath_table的两个调用并且连接结果:
test=# SELECT t.*,i.doc_num FROM
test-# xpath_table('id', 'xml', 'test',
test(# '/doc/line/@num|/doc/line/a|/doc/line/b|/doc/line/c',
test(# 'true')
test-# AS t(id int, line_num varchar(10), val1 int, val2 int, val3 int),
test-# xpath_table('id', 'xml', 'test', '/doc/@num', 'true')
test-# AS i(id int, doc_num varchar(10))
test-# WHERE i.id=t.id AND i.id=1
test-# ORDER BY doc_num, line_num;
id | line_num | val1 | val2 | val3 | doc_num
----+----------+------+------+------+---------
1 | L1 | 1 | 2 | 3 | C1
1 | L2 | 11 | 22 | 33 | C1
(2 rows)
XSLT 函数
如果安装了 libxslt,那么可以使用下列函数:
D.45.4.1. xslt_process
xslt_process(text document, text stylesheet, text paramlist) returns text
这个函数将 XSL 样式表应用于文档并且返回转换过的结果。paramlist是一个被用在转换中的参数赋值列表,以a=1,b=2的形式指定。注意参数解析是非常天真的:参数值不能包含逗号!