掌握 XPath、XQuery 和 XSLT 函数提升开发效率(二)

XPath、XQuery 和 XSLT 是处理 XML 数据的强大工具。本文将详细介绍这些技术中的常用函数,帮助你在实际开发中更高效地操作 XML 文档。通过学习这些函数,你将能够更灵活地解析、转换和生成 XML 数据,提升开发效率。

1. 基础知识

XPath、XQuery 和 XSLT 都依赖于一组标准函数来处理数据。这些函数涵盖了从基本的数据访问到复杂的错误处理和调试功能。函数的命名空间默认前缀为 fn,其 URI 为 http://www.w3.org/2005/xpath-functions

2. 数据访问函数

2.1 节点名称和属性

  • fn:node-name(node): 返回指定节点的名称。
  • fn:nilled(node): 检查节点是否被标记为 nil,返回布尔值。
  • fn:data(item, item, ...): 接受一个项目序列并返回相应的原子值序列。
  • fn:base-uri()fn:base-uri(node): 返回当前节点或指定节点的 base-uri 属性值。
  • fn:document-uri(node): 返回指定节点的 document-uri 属性值。

示例


<book>

<title>XML in Action</title>

<author>John Doe</author>
</book>
fn:node-name(/book/title)  <!-- 返回 "title" -->
fn:nilled(/book/title)     <!-- 返回 false -->
fn:data(/book/author)      <!-- 返回 "John Doe" -->
fn:base-uri(/book)         <!-- 返回当前节点的 base-uri -->
fn:document-uri(/book)     <!-- 返回当前节点的 document-uri -->

3. 错误和调试函数

3.1 错误处理

  • fn:error(): 抛出一个错误,可选参数包括错误代码、描述和错误对象。
  • fn:trace(value, label): 用于调试,记录特定值及其标签。

示例

fn:error(fn:QName('http://example.com/test', 'err:toohigh'), 'Error: Price is too high')

上述代码会抛出一个带有错误代码 http://example.com/test#toohigh 和描述 "Error: Price is too high" 的错误。

4. 数值处理函数

4.1 基本数值操作

  • fn:number(arg): 将参数转换为数值。
  • fn:abs(num): 返回参数的绝对值。
  • fn:ceiling(num): 返回大于或等于参数的最小整数。
  • fn:floor(num): 返回小于或等于参数的最大整数。
  • fn:round(num): 四舍五入参数到最接近的整数。
  • fn:round-half-to-even(num): 四舍六入五成双。

示例

fn:number('100')        <!-- 返回 100 -->
fn:abs(-3.14)           <!-- 返回 3.14 -->
fn:ceiling(3.14)        <!-- 返回 4 -->
fn:floor(3.14)          <!-- 返回 3 -->
fn:round(3.14)          <!-- 返回 3 -->
fn:round-half-to-even(0.5)  <!-- 返回 0 -->
fn:round-half-to-even(1.5)  <!-- 返回 2 -->

5. 字符串处理函数

5.1 基本字符串操作

  • fn:string(arg): 将参数转换为字符串。

  • fn:codepoints-to-string(int, int, ...): 根据代码点序列返回字符串。

  • fn:string-to-codepoints(string): 根据字符串返回代码点序列。

  • fn:codepoint-equal(comp1, comp2): 比较两个代码点是否相等。

  • fn:compare(comp1, comp2): 比较两个字符串,返回 -1、0 或 1。

  • fn:concat(string, string, ...): 连接多个字符串。

  • fn:string-join((string, string, ...), sep): 使用指定分隔符连接字符串序列。

  • fn:substring(string, start, len): 返回从指定位置开始的子字符串。

  • fn:string-length(string): 返回字符串的长度。

  • fn:normalize-space(string): 去除字符串首尾的空白,并将内部的连续空白替换为单个空格。

  • fn:normalize-unicode(string): 执行 Unicode 规范化。

  • fn:upper-case(string): 将字符串转换为大写。

  • fn:lower-case(string): 将字符串转换为小写。

  • fn:translate(string1, string2, string3): 将 string1 中的 string2 替换为 string3。

  • fn:escape-uri(stringURI, esc-res): 对 URI 进行转义。

  • fn:contains(string1, string2): 检查 string1 是否包含 string2。

  • fn:starts-with(string1, string2): 检查 string1 是否以 string2 开头。

  • fn:ends-with(string1, string2): 检查 string1 是否以 string2 结尾。

  • fn:substring-before(string1, string2): 返回 string2 在 string1 中出现之前的子字符串。

  • fn:substring-after(string1, string2): 返回 string2 在 string1 中出现之后的子字符串。

  • fn:matches(string, pattern): 检查 string 是否匹配指定的正则表达式。

  • fn:replace(string, pattern, replace): 将 string 中匹配 pattern 的部分替换为 replace。

  • fn:tokenize(string, pattern): 使用正则表达式将字符串分割为多个子字符串。

示例

fn:string(314)                  <!-- 返回 "314" -->
fn:codepoints-to-string(84, 104, 233, 114, 232, 115, 101)  <!-- 返回 "Thérèse" -->
fn:string-to-codepoints("Thérèse")  <!-- 返回 84, 104, 233, 114, 232, 115, 101 -->
fn:compare('abc', 'def')        <!-- 返回 -1 -->
fn:concat('XPath ', 'is ', 'FUN!')  <!-- 返回 "XPath is FUN!" -->
fn:string-join(('We', 'are', 'having', 'fun!'), ' ')  <!-- 返回 "We are having fun!" -->
fn:substring('Beatles', 1, 4)   <!-- 返回 "Beat" -->
fn:string-length('Beatles')     <!-- 返回 7 -->
fn:normalize-space(' The   XML ')  <!-- 返回 "The XML" -->
fn:upper-case('The XML')        <!-- 返回 "THE XML" -->
fn:translate('12:30', '30', '45')  <!-- 返回 "12:45" -->
fn:escape-uri("http://example.com/test#car", true())  <!-- 返回 "http%3A%2F%2Fexample.com%2Ftest#car" -->
fn:contains('XML', 'XM')        <!-- 返回 true -->
fn:starts-with('XML', 'X')      <!-- 返回 true -->
fn:ends-with('XML', 'X')        <!-- 返回 false -->
fn:substring-before('12/10', '/')  <!-- 返回 "12" -->
fn:substring-after('12/10', '/')   <!-- 返回 "10" -->
fn:matches("Merano", "ran")     <!-- 返回 true -->
fn:replace("Bella Italia", "l", "*")  <!-- 返回 "Be**a Ita*ia" -->
fn:tokenize("XPath is fun", "\s+")  <!-- 返回 ("XPath", "is", "fun") -->

6. URI 处理函数

6.1 解析和构建 URI

  • fn:resolve-uri(relative, base): 解析相对 URI 并返回绝对 URI。

示例

fn:resolve-uri("test.html", "http://example.com/")  <!-- 返回 "http://example.com/test.html" -->

7. 布尔值处理函数

7.1 基本布尔操作

  • fn:boolean(arg): 将参数转换为布尔值。
  • fn:not(arg): 取反布尔值。
  • fn:true(): 返回 true。
  • fn:false(): 返回 false。

示例

fn:boolean(0)  <!-- 返回 false -->
fn:not(true()) <!-- 返回 false -->
fn:true()      <!-- 返回 true -->
fn:false()     <!-- 返回 false -->

8. 日期和时间处理函数

8.1 日期和时间组件提取

  • fn:dateTime(date, time): 将日期和时间组合为 dateTime 类型。

  • fn:years-from-duration(datetimedur): 提取 duration 的年份部分。

  • fn:months-from-duration(datetimedur): 提取 duration 的月份部分。

  • fn:days-from-duration(datetimedur): 提取 duration 的天数部分。

  • fn:hours-from-duration(datetimedur): 提取 duration 的小时部分。

  • fn:minutes-from-duration(datetimedur): 提取 duration 的分钟部分。

  • fn:seconds-from-duration(datetimedur): 提取 duration 的秒数部分。

  • fn:year-from-dateTime(datetime): 提取 dateTime 的年份部分。

  • fn:month-from-dateTime(datetime): 提取 dateTime 的月份部分。

  • fn:day-from-dateTime(datetime): 提取 dateTime 的天数部分。

  • fn:hours-from-dateTime(datetime): 提取 dateTime 的小时部分。

  • fn:minutes-from-dateTime(datetime): 提取 dateTime 的分钟部分。

  • fn:seconds-from-dateTime(datetime): 提取 dateTime 的秒数部分。

  • fn:timezone-from-dateTime(datetime): 提取 dateTime 的时区部分。

  • fn:year-from-date(date): 提取 date 的年份部分。

  • fn:month-from-date(date): 提取 date 的月份部分。

  • fn:day-from-date(date): 提取 date 的天数部分。

  • fn:timezone-from-date(date): 提取 date 的时区部分。

  • fn:hours-from-time(time): 提取 time 的小时部分。

  • fn:minutes-from-time(time): 提取 time 的分钟部分。

  • fn:seconds-from-time(time): 提取 time 的秒数部分。

  • fn:timezone-from-time(time): 提取 time 的时区部分。

  • fn:adjust-dateTime-to-timezone(datetime, timezone): 调整 dateTime 的时区。

  • fn:adjust-date-to-timezone(date, timezone): 调整 date 的时区。

  • fn:adjust-time-to-timezone(time, timezone): 调整 time 的时区。

示例

fn:year-from-dateTime(xs:dateTime("2005-01-10T12:30-04:10"))  <!-- 返回 2005 -->
fn:month-from-dateTime(xs:dateTime("2005-01-10T12:30-04:10"))  <!-- 返回 01 -->
fn:day-from-dateTime(xs:dateTime("2005-01-10T12:30-04:10"))  <!-- 返回 10 -->
fn:hours-from-dateTime(xs:dateTime("2005-01-10T12:30-04:10"))  <!-- 返回 12 -->
fn:minutes-from-dateTime(xs:dateTime("2005-01-10T12:30-04:10"))  <!-- 返回 30 -->
fn:seconds-from-dateTime(xs:dateTime("2005-01-10T12:30:00-04:10"))  <!-- 返回 0 -->
fn:timezone-from-dateTime(xs:dateTime("2005-01-10T12:30-04:10"))  <!-- 返回 "-04:10" -->
fn:year-from-date(xs:date("2005-04-23"))  <!-- 返回 2005 -->
fn:month-from-date(xs:date("2005-04-23"))  <!-- 返回 4 -->
fn:day-from-date(xs:date("2005-04-23"))  <!-- 返回 23 -->
fn:timezone-from-date(xs:date("2005-04-23"))  <!-- 返回 "" -->
fn:hours-from-time(xs:time("10:22:00"))  <!-- 返回 10 -->
fn:minutes-from-time(xs:time("10:22:00"))  <!-- 返回 22 -->
fn:seconds-from-time(xs:time("10:22:00"))  <!-- 返回 0 -->
fn:timezone-from-time(xs:time("10:22:00"))  <!-- 返回 "" -->
fn:adjust-dateTime-to-timezone(xs:dateTime("2005-01-10T12:30-04:10"), xs:dayTimeDuration("PT5H"))  <!-- 返回 "2005-01-10T17:30-04:10" -->
fn:adjust-date-to-timezone(xs:date("2005-04-23"), xs:dayTimeDuration("PT5H"))  <!-- 返回 "2005-04-23+05:00" -->
fn:adjust-time-to-timezone(xs:time("10:22:00"), xs:dayTimeDuration("PT5H"))  <!-- 返回 "15:22:00+05:00" -->

9. QName 处理函数

9.1 QName 操作

  • fn:QName(namespaceURI, localPart): 创建一个 QName。
  • fn:local-name-from-QName(QName): 提取 QName 的本地部分。
  • fn:namespace-uri-from-QName(QName): 提取 QName 的命名空间 URI。
  • fn:namespace-uri-for-prefix(prefix, element): 获取指定前缀的命名空间 URI。
  • fn:in-scope-prefixes(element): 获取元素作用域内的所有前缀。
  • fn:resolve-QName(QName, element): 解析 QName。

示例

fn:QName("http://example.com/", "test")  <!-- 返回 "http://example.com/:test" -->
fn:local-name-from-QName(fn:QName("http://example.com/", "test"))  <!-- 返回 "test" -->
fn:namespace-uri-from-QName(fn:QName("http://example.com/", "test"))  <!-- 返回 "http://example.com/" -->
fn:namespace-uri-for-prefix("x", /element)  <!-- 返回 "http://example.com/" -->
fn:in-scope-prefixes(/element)  <!-- 返回 ("x", "y", "z") -->
fn:resolve-QName("x:test", /element)  <!-- 返回 "http://example.com/:test" -->

10. 节点处理函数

10.1 节点操作

  • fn:name()fn:name(nodeset): 返回当前节点或指定节点集中的第一个节点的名称。
  • fn:local-name()fn:local-name(nodeset): 返回当前节点或指定节点集中的第一个节点的本地名称。
  • fn:namespace-uri()fn:namespace-uri(nodeset): 返回当前节点或指定节点集中的第一个节点的命名空间 URI。
  • fn:lang(lang): 检查当前节点的语言是否匹配指定的语言。
  • fn:root()fn:root(node): 返回当前节点或指定节点所属的节点树的根节点。

示例

<book xml:lang="en">

<title>XML in Action</title>

<author>John Doe</author>
</book>
fn:name(/book/title)  <!-- 返回 "title" -->
fn:local-name(/book/title)  <!-- 返回 "title" -->
fn:namespace-uri(/book/title)  <!-- 返回 "" -->
fn:lang("en", /book)  <!-- 返回 true -->
fn:root(/book/title)  <!-- 返回 /book 的根节点 -->

11. 序列处理函数

11.1 序列操作

  • fn:index-of((item, item, ...), searchitem): 返回项目序列中等于 searchitem 的索引。
  • fn:empty(sequence): 检查序列是否为空。
  • fn:exists(sequence): 检查序列是否存在。
  • fn:count(sequence): 返回序列中的项目数量。
  • fn:distinct-values(sequence): 返回序列中的唯一值。
  • fn:reverse(sequence): 反转序列。
  • fn:subsequence(sequence, start, length): 返回从指定位置开始的子序列。
  • fn:unordered(sequence): 返回无序的序列。
  • fn:insert-before(sequence, position, insert-item): 在指定位置插入项目。
  • fn:remove(sequence, position): 移除指定位置的项目。
  • fn:deep-equal(sequence1, sequence2): 检查两个序列是否深度相等。

示例

fn:index-of((1, 2, 3, 4), 3)  <!-- 返回 3 -->
fn:empty(() )  <!-- 返回 true -->
fn:exists((1, 2, 3))  <!-- 返回 true -->
fn:count((1, 2, 3))  <!-- 返回 3 -->
fn:distinct-values((1, 2, 2, 3, 3, 3))  <!-- 返回 (1, 2, 3) -->
fn:reverse((1, 2, 3))  <!-- 返回 (3, 2, 1) -->
fn:subsequence((1, 2, 3, 4, 5), 2, 3)  <!-- 返回 (2, 3, 4) -->
fn:unordered((1, 2, 3))  <!-- 返回 (1, 2, 3) 或其他无序排列 -->
fn:insert-before((1, 2, 3), 2, 0)  <!-- 返回 (1, 0, 2, 3) -->
fn:remove((1, 2, 3), 2)  <!-- 返回 (1, 3) -->
fn:deep-equal((1, 2, 3), (1, 2, 3))  <!-- 返回 true -->

总结

通过本文,我们详细介绍了 XPath、XQuery 和 XSLT 中的各种函数,涵盖了从基础的数据访问到高级的错误处理和调试功能。这些函数在处理 XML 数据时非常有用,可以帮助你更高效地完成各种任务。希望本文能为你在实际开发中提供有价值的参考。如果你有任何问题或建议,欢迎在评论区留言。