本文提供 5 个关于在工作中使用 XPath 的技巧 — 都来自实际的应用程序,对于这些应用程序,花了很多时间深入研究 XPath 的一些混乱的、非预期的行为:
- False 有时是 true。
- XPath 表达式
(x != y)
和not(x = y)
是不同的,结果也不同。 - XPath
position()
函数的值随着它的上下文而改变。 - 利用 XPath 选择一个给定名称的第一个元素。
- 调试因默认名称空间而失败的 XPath
select
表达式。
利用这些技巧,可以少花很多时间在迷茫中摸索。
长度大于 0 的字符串在解析为 Boolean 函数时,总是被判断为 True,即使它的值是字符串 'false'
时亦是如此。
在 XPath 表达式中,比较字符串和 Boolean 函数会得到非预期的结果。为了避免出现麻烦,不要将字符串与内置的 Boolean 函数 true()
和 false()
进行比较。相反,应该将字符串与字符串值 'true'
和 'false'
比较。保持 Boolean 函数 true()
和 false()
为 Booleans 值,不让它们被意外地转换成字符串,是很困难的。非空字符串被认为是 True,即使它的值是 'false'
时亦是如此;因此,boolean('false') = true()
和 boolean('true') = true()
都成立。只有空字符串 (''
) 是 False — 即 boolean('') = false()
。
考虑 Boolean 函数转换成字符串以及再转换回来时会出现的非预期结果。首先,Boolean 被转换成字符串(例如,string(false()) = 'false'
)。当转换回来时,如 boolean(string(false()))
中所示,结果是 true()
。
但是 string()
函数并不是将 Boolean 函数转换成字符串的惟一方法。结果树片段(Result tree fragment,RTF)— 有时是不可避免的— 是字符串。例如,来看一下 清单 1,这是一个内容为文档及其名称、发布年份和页数的 XML 文档。
清单 1. XML 源文档
<Documents> <Document id="18396"> <Name>Knowing the Good</Name> <Year>2010</Year> <Pages>35</Pages> </Document> <Document id="18397"> <Name>Beyond Standards: Best Practices</Name> <Year>2011</Year> <Pages>12</Pages> </Document> <Document id="18398"> <Name>101 Ways to Do the Same Thing</Name> <Year>2011</Year> <Pages>50</Pages> </Document> </Documents> |
清单 2 是一个 XSLT 模板,用于搜索不少于 20 页的最近文档。可是,该模板产生了不正确的结果。
清单 2. 错误的 XSLT 模板
<xsl:template match="Document"> <xsl:variable name="recentFullLengthPublications"> <xsl:choose> <xsl:when test="Year=2011 and Pages >= 20"> <xsl:value-of select="true()"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="false()"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:if test="$recentFullLengthPublications"> <xsl:copy-of select="Name"/> </xsl:if> </xsl:template> |
转换返回 清单 3 中的 XML,是不正确的。应该只返回一个元素 — 即 “101 Ways to Do the Same Thing”。但是,实际上所有 3 个元素都返回了。
清单 3. 不正确的结果
<Name>Knowing the Good</Name> <Name>Beyond Standards: Best Practices</Name> <Name>101 Ways to Do the Same Thing</Name> |
名为 “101 Ways to Do the Same Thing” 的文档是 2011 年惟一一个不少于 20 页的文档,那么哪里出错了呢?变量的内容产生一个 RTF。这个片段被判断为字符串,即使它的值是 Boolean 函数。
清单 2 中 的 <xsl:if test="$recentFullLengthPublications">
中的测试表达式是不正确的。该测试总是为 True;源文档中的所有 <Name>
元素都被返回。甚至 <xsl:if test="$recentFullLengthPublications=true()">
中的测试表达式也是不正确的。变量 $recentFullLengthPublications
将是字符串 'true'
或者 'false'
,不是 Boolean 数据类型。因此,语句 <xsl:if test="$recentFullLengthPublications='true'">
确实 能够工作。
但是,模板有些混乱,因为它使用了 true()
和 false()
函数,它们俩在本例中是有误导性的。清单 4 中的模板既正确,又更加可读。它使用 'yes'
和 'no'
取代 'true'
和 'false'
,以避免与 Boolean 类型混淆。记住用单引号括住 'yes'
和 'no'
。
清单 4. 正确的 XSLT 模板
<xsl:template match="Document"> <xsl:variable name="recentFullLengthPublications"> <xsl:choose> <xsl:when test="Year=2011 and Pages >= 20"> <xsl:value-of select="'yes'"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="'no'"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:if test="$recentFullLengthPublications='yes'"> <xsl:copy-of select="Name"/> </xsl:if> </xsl:template> |
当心 Boolean 函数 true()
和 false()
。在这个简单的例子中,不必使用变量,若使用的话,应该定义为具有 select
属性。带有 select
属性的结果不被自动转换成字符串;因此,Boolean 值保持为 Boolean 值。select
属性不返回 RTF。
通常,条件对于 select
属性来说太复杂了,您必须将变量定义为 RTF。对于这个简单的例子,清单 5 和 清单 6 中的模板都是首选的。在 清单 5 中,测试不需要与字符串进行比较,因为变量返回一个 Boolean 类型而不是 RTF 作为 select
属性的结果。
清单 5. 改进的简单 XSLT 模板
<xsl:template match="Document"> <xsl:variable name="recentFullLengthPublications" select="Year=2011 and Pages >= 20" /> <xsl:if test="$recentFullLengthPublications"> <xsl:copy-of select="Name"/> </xsl:if> </xsl:template> |
另外,您也可以不使用变量,如 清单 6 中所示,因为条件很简单。但是,变量是自我注解的(self-documenting)。
清单 6. 备选的简单 XSLT 模板
<xsl:template match="Document"> <xsl:if test="Year=2011 and Pages >= 20"> <xsl:copy-of select="Name"/> </xsl:if> </xsl:template> |
技巧 2:知道 (x != y) 与 not(x = y) 之间的区别
XPath 表达式 (x != y)
和 not(x = y)
是不同的。
简单总结如下:
(x != y)
选择既带有 x 又带有 y 但是二者值不相同的节点。这个表达式比not(x = y)
限制更严格,因为它选择的节点必须具有 x 和 y。not(x = y)
选择缺少 x 和 y 二者之一、或者具有 x 和 y 但是二者值不相同的节点。该表达式的限制更宽松。
对于大多数计算机语言,表达式 x != y 和 not(x = y) 是等价的;但是对于 XML,值是不明确的,因为缺失一个节点。比较 XML 节点值时,问题出现了:缺少的值应该如何被评估?对于一个简单的等价性比较,考虑 x = y
:如果 x 和 y 二者之一缺失,那么结果是 false。另一个问题是,表达式应该如何被否定?下面的例子回答了这个问题。
清单 7 是一个关于文档的 XML 文档。可以查询数据,以找到在给定年份发布的或者页数在某个范围内的文档。最新的文档 —“Prospective Projects”— 不具有年份或页数。该文档是不完全的,因此还没有发布。
清单 7. XML 源文档
<Documents> <Document id="18396"> <Name>Knowing the Good</Name> <Year>2010</Year> <Pages>35</Pages> </Document> <Document id="18397"> <Name>Beyond Standards: Best Practices</Name> <Year>2011</Year> <Pages>12</Pages> </Document> <Document id="18398"> <Name>101 Ways to Do the Same Thing</Name> <Year>2011</Year> <Pages>50</Pages> </Document> <Document id="18399"> <Name>Prospective Projects</Name> </Document> </Documents> |
XPath 表达式 //Document[Year = 2011]/Name
选择在 2011 年发布的文档。清单 8 显示,结果是两个文档。
清单 8. 2011 年发布的文档
<Name>Beyond Standards: Best Practices</Name> <Name>101 Ways to Do the Same Thing</Name> |
接下来,考虑如何选择不是 2011 年发布的文档。存在两种否定 XPath 表达式的方式:not()
和 !=
。利用 XPath 表达式 //Document[not(Year = 2011)]/Name
,可选择所有不在 2011 文档集中的文档。清单 9 显示,结果是另外两个文档。
清单 9. 不是 2011 年发布的文档
<Name>Knowing the Good</Name> <Name>Prospective Projects</Name> |
要选择所有不是 2011 年发布的文档,可以使用表达式 //Document[Year != 2011]/Name
。结果是 清单 10,其中只展示了单个文档。
清单 10. 不是 2011 年发布的文档
<Name>Knowing the Good</Name> |
如上所示,not(Year = 2011)
和Year != 2011
这两个 XPath 表达式具有稍微不同的含义。您使用 XPath 表达式 //Document[Pages >= 20]/Name
来获得所有不少于 20 页的文档。结果是 清单 11,其中展示了两个匹配条件的文档。
清单 11. 长文档
<Name>Knowing the Good</Name> <Name>101 Ways to Do the Same Thing</Name> |
接下来,考虑相反的情况:少于 20 页的文档。表达式 //Document[Pages < 20]/Name
选择这些文档。惟一匹配的文档是 清单 12 中的结果。
清单 12. 短文档
<Name>Beyond Standards: Best Practices</Name> |
最后,注意 "Prospective Projects" 不具有已知的页数。包括用 not()
而不是 !=
得到的文档 — 例如,//Document[not(Pages >= 20)]/Name
。结果是 清单 13,带有两个文档。
清单 13. 少于 20 页或者未知页数的文档
<Name>Beyond Standards: Best Practices</Name> <Name>Prospective Projects</Name> |
要得到未知页数的文档列表,可使用 XPath 表达式 //Document[not(Pages)]/Name
。清单 14 展示了匹配条件的文档。
清单 14. 未知页数的文档
<Name>Prospective Projects</Name> |
not()
函数对于处理带有缺失属性或元素的节点非常重要。参见 参考资料 中的链接,了解关于 XPath 的更多技巧。
position()
函数的值取决于它的上下文 — 它用在哪里。当它用在谓词中时,尤其存在这种依赖性。
position()
函数返回节点集中节点的基于 1 的索引。position()
函数计数节点 —元素和文本节点— 即使文本只是空白。下面的例子演示了几种不同上下文中的 position()
。
清单 15 是一个内容为文档及作者的 XML 文档。有趣的是 <Name>
元素。
清单 15. XML 源文档
<Documents> <Document id="18396"> <Name>Knowing the Good</Name> <Authors> <Name>Bob Bloggs</Name> <Name>Kim Bergess</Name> </Authors> </Document> <Document id="18397"> <Name>Beyond Standards: Best Practices</Name> <Authors> <Name>Bill Agnew</Name> </Authors> </Document> <Document id="18398"> <Name>101 Ways to Do the Same Thing</Name> <Authors> <Name>Jay Nerks</Name> <Name>Paula Towne</Name> <Name>Carol Tinney</Name> </Authors> </Document> </Documents> |
清单 16 中的 XSLT 模板显示了每个 <Name>
元素的位置。清单 17 展示了结果。
清单 16. 使用 position() 的 XSLT 模板
<xsl:template match="Name"> <xsl:value-of select="concat(position(),' ',.,' ')"/> </xsl:template> |
第一列是 position()
函数的值。清单 17 展示了 XSLT 模板转换的结果。
清单 17. 清单 16 的结果
2 Knowing the Good 2 Bob Bloggs 4 Kim Bergess 2 Beyond Standards: Best Practices 2 Bill Agnew 2 101 Ways to Do the Same Thing 2 Jay Nerks 4 Paula Towne 6 Carol Tinney |
结果列出了 <Name>
元素在模板上下文中的位置。即使大多数 name 元素是它们父元素中的第一个元素,它们其实是第二个节点,因为标记之间存在一个空文本节点(包含一个换行)。此外,位置是相对于它的父元素,而不是整个文档。
清单 18 中的模板将 <Name>
元素从文本节点中分离出来。
清单 18. 两个 XSLT 模板
<xsl:template match="Documents"> <xsl:apply-templates select="//Name"/> </xsl:template> <xsl:template match="Name"> <xsl:value-of select="concat(position(),' ',.,' ')"/> </xsl:template> |
空白文本节点被省略后的结果是 清单 19。position()
函数的值显示在第一列中。
清单 19. 清单 18 的结果
1 Knowing the Good 2 Bob Bloggs 3 Kim Bergess 4 Beyond Standards: Best Practices 5 Bill Agnew 6 101 Ways to Do the Same Thing 7 Jay Nerks 8 Paula Towne 9 Carol Tinney |
第一个模板选择并处理所有的 <Name>
元素。由于所有 9 个 <Name>
元素被选择为一个集合,所以 position()
是该集合中一个元素的索引。
在下一个例子中,position()
函数用在 xsl:apply-templates
语句的谓词中,选择具有位置 1 的名称。参见 清单 20。
清单 20. 在谓词中使用 position() 的模板
<xsl:template match="Documents"> <xsl:apply-templates select="//Name[position()=1]"/> </xsl:template> <xsl:template match="Name"> <xsl:value-of select="concat(position(),' ',.,' ')"/> </xsl:template> |
结果是 清单 21。注意,只返回了 6 个条目。第一列是 position()
函数的值,这些 Name
元素是它们父元素中的第一个元素。
清单 21. 清单 20 的结果
1 Knowing the Good 2 Bob Bloggs 3 Beyond Standards: Best Practices 4 Bill Agnew 5 101 Ways to Do the Same Thing 6 Jay Nerks |
注意,只包括第一个作者。当您在谓词 — 即方括号 ([]
) — 中使用 position()
时,索引是相对于 <Name>
元素的父元素的。只返回 <Authors>
元素中的第一个 <Name>
元素。作为一种快捷方式,Name[position()=1]
可以表达为 Name[1]
。
清单 22 包含一个模板,其中 position()
函数放置在模板的 match
表达式而不是 xsl:apply-templates
语句中。第三个模板丢弃不在位置 1 的 Name
元素。
清单 22. 使用 position() 匹配谓词
<xsl:template match="Documents"> <xsl:apply-templates select="//Name"/> </xsl:template> <xsl:template match="Name[position()=1]"> <xsl:value-of select="concat(position(),' ',.,' ')"/> </xsl:template> <xsl:template match="Name" /> |
清单 23 中提供的结果是跟前面相同的 6 个元素,但是位置不同。
清单 23. 清单 22 的结果
1 Knowing the Good 2 Bob Bloggs 4 Beyond Standards: Best Practices 5 Bill Agnew 6 101 Ways to Do the Same Thing 7 Jay Nerks |
清单 23 中的名称与 清单 21 中的相同,但是位置值不同。所有 9 个名称都应用于模板,但是只有 6 个匹配,而 清单 20 中,只有 6 个应用于模板。作为一种快捷方式,Name[position()=1]
可以表达为 Name[1]
。
清单 24 展示了只处理 XML 文档中第一个 <Name>
元素的模板。
清单 24. 在应用之前过滤后的元素
<xsl:template match="Documents"> <xsl:apply-templates select="(//Name)[1]"/> </xsl:template> <xsl:template match="Name"> <xsl:value-of select="concat(position(),' ',.,' ')"/> </xsl:template> |
清单 25 展示了单个结果。
清单 25. 清单 24 的结果
1 Knowing the Good |
select
属性中使用的括号 (()
) 对于正确的行为很重要。谓词 [1]
与 [position()=1]
相同。
检查第二个模板而不是第一个模板中的位置会将决策从模板调用者转移到模板本身,如 清单 26 中所示。
清单 26. 应用之后过滤后的元素
<xsl:template match="Documents"> <xsl:apply-templates select="//Name"/> </xsl:template> <xsl:template match="Name"> <xsl:if test="position()=1"> <xsl:value-of select="concat(position(),' ',.,' ')"/> </xsl:if> </xsl:template> |
位置检查已经移动到模板本身中。该检查是 xsl:if
语句而不是 match
表达式中谓词的一部分。如果谓词在模板的 match
表达式(即 <xsl:template match="Name[1]">
)中,那么结果是 清单 23 中的元素。清单 26 的结果在 清单 27 中给出。
清单 27. 清单 26 的结果
1 Joe Bloggs |
清单 28 包含一个模板,它忽略会影响 清单 17 中 <Name>
元素的位置的那些空白文本节点。
清单 28. 忽略文本节点的模板
<xsl:template match="*"> <xsl:apply-templates select="*"/> </xsl:template> <xsl:template match="Name"> <xsl:value-of select="concat(position(),' ',.,' ')"/> </xsl:template> |
清单 29 展示了忽略文本节点后的结果。
清单 29. 清单 28 的结果
1 Knowing the Good 1 Bob Bloggs 2 Kim Bergess 1 Beyond Standards: Best Practices 1 Bill Agnew 1 101 Ways to Do the Same Thing 1 Jay Nerks 2 Paula Towne 3 Carol Tinney |
position()
函数返回不同的结果,取决于它使用在哪里以及它是在模板的 match
表达式中、谓词中,还是 xsl:apply-templates
的选定节点集中。
使用 //Name[not(preceding::Name)]
(这对于模板匹配是必需的)或者 (//Name)[1]
(使用在 select
属性中),您可以选择 XML 文档中第一个具有名称 Name
的元素。对于选择元素集合中的第一个元素,最容易的方法是利用值 1
的谓词。例如,清单 30 是一个 XML 文档,内容为文档及其名称、发布年份和页数。
清单 30. XML 源文档
<Documents> <Document id="18396"> <Name>Knowing the Good</Name> <Year>2010</Year> <Pages>35</Pages> </Document> <Document id="18397"> <Name>Beyond Standards: Best Practices</Name> <Year>2011</Year> <Pages>12</Pages> </Document> <Document id="18398"> <Name>101 Ways to Do the Same Thing</Name> <Year>2011</Year> <Pages>50</Pages> </Document> </Documents> |
XPath 表达式 //Document[1]
— 或者 /Documents/Document[1]
— 选择第一个文档元素。结果是 清单 31。
清单 31. 第一个文档
<Document id="18396"> <Name>Knowing the Good</Name> <Year>2010</Year> <Pages>35</Pages> </Document> |
XPath 表达式选择 <Document>
元素列表,然后返回第一个元素。谓词 [1]
表示 “具有位置 1 的元素”。另一种表达这一含义的方式是 //Document[position()=1]
。
接下来,考虑如何选择第一个文档的名称。<Name>
元素是 <Document>
元素的一个子节点。通过将其标记名称附加到 XPath — 即 //Document[1]/Name
,这返回第一个 <Document>
元素的 <Name>
元素 — 而选择该子节点 。结果是 清单 32。
清单 32. 第一个文档的 Name 元素
<Name>Knowing the Good</Name> |
XPath 表达式 //Name[1]
选择第一个 <Name>
元素,无论它位于 XML 文档中的何处;但是,这里有一个问题。清单 33 展示了非预期的结果。返回了三个而不是一个元素。
清单 33. 非预期的结果
<Name>Knowing the Good</Name> <Name>Beyond Standards: Best Practices</Name> <Name>101 Ways to Do the Same Thing</Name> |
只预期一个元素,却返回三个元素。每个<Document>
元素中的第一个 <Name>
元素被选中。如果一个 <Document>
元素包含不止一个 <Name>
元素,那么只会返回第一个。
您如何选择 XML 文档中的第一个 <Name>
元素取决于您如何使用 XPath。在一个 XSLT 模板 match
属性中,选择比利用 select
属性更加有限。对于 match
XPath 表达式,使用 XPath 轴 preceding
来选择第一个元素。清单 34 演示了该表达式。
清单 34. 使用 preceding 轴的模板匹配
<xsl:template match="//Name[not(preceding::Name)]"> |
预期的结果是第一个元素,展示在 清单 35 中。
清单 35. 清单 34 中模板的结果
<Name>Knowing the Good</Name> |
该表达式的含义是 “选择 XML 文档中较早的不具有 <Name>
元素的 <Name>
元素”。
对于 select
表达式,比如说 xsl:apply-templates
语句,XPath 更加灵活。尽管 清单 34 中的表达式能够工作,但是使用慎重应用的括号则更为清晰,并且容易改编来选择第二个、第三个或者任何其他索引。参见 清单 36。
清单 36. 使用 preceding 轴的模板匹配
<xsl:apply-templates select="(//Name)[1]"/> |
清单 37. 清单 36 中模板的结果
<Name>Knowing the Good</Name> |
该表达式选择所有的 <Name>
元素,然后返回第一个元素。
选择想要的结果时,括号和轴的慎重放置是至关重要的。
技巧 5:处理不能匹配具有默认名称空间的文档的 XPath 选择表达式
XSLT 的默认名称空间不适用于它的 XPath 表达式。存在三种可能的解决方案:
- 删除 XML 文档的默认名称空间。
- 向 XPath 表达式添加名称空间前缀。
- 进行预处理,以删除名称空间。
如果 XML 文档不能修改,则删除默认的名称空间。清单 38 是一个带有默认名称空间的 XHTML 文档 — 根据定义,是一个 XML 文档。
清单 38. 带有默认名称空间的 XHTML 文档
<?xml version="1.0"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>This is the title</title> </head> <body> <p>Hello world.</p> </body> </html> |
清单 39 是一个 XSLT,其中 XML 文档的默认名称空间被分配一个前缀。为本例选择了前缀 xhtml
,但是任何前缀都是可接受的。
清单 39. 使用名称空间前缀的 XSLT
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml" exclude-result-prefixes="xhtml" > <xsl:output method="xml" version="1.0"/> <xsl:template match="xhtml:title"> <title>Replaced with a new title</title> </xsl:template> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet> |
清单 40 展示了生成的 XHTML 文档。<title>
元素中的文本已经被正确替换。通过在 XSLT 中使用 exclude-result-prefixes
属性,xhtml:
前缀已从转换的输出文档中排除。
清单 40. 转换的 XHTML 文档
<?xml version="1.0"?> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Replaced with a new title</title> </head> <body> <p>Hello world.</p> </body> </html> |
利用一个 XSLT 对 XML 文档进行预处理以删除其中的名称空间也是一种解决方案,但是这样做可能比较费时间。清单 41 中的 XSLT 复制源 XML 文档中的文本、元素和属性节点,但是忽略名称空间节点和 DOCTYPE 声明。
清单 41. 用于删除名称空间节点的 XSLT
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0"/> <!-- copy elements without namespace --> <xsl:template match="*"> <xsl:element name="{name()}"> <xsl:apply-templates select="node()|@*"/> </xsl:element> </xsl:template> <xsl:template match="@*|text()|processing-instruction()|comment()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet> |
这个两段式方法转换文档两次,结果是第二个 XSLT 转换第一个 XSLT 得到的结果。有关多阶段转换的更多信息,参见 参考资料。
选项 1(如果您可以应用它的话)是最容易、最简单的解决方案。如果 XML 文档一直具有默认的名称空间(通常有这种情况),那么 选项 2 是可能的。尽管向 XPath 表达式添加名称空间前缀需要进行一点额外的录入,但是该解决方案可行,且不增加额外的处理。选项 3 处理 XML 文档两次,因此也更慢。但是,不必关心源 XML 文档是否具有默认的名称空间。
XPath 表达式中的二进制逻辑比简单的 true 和 false 要稍微复杂一点。当比较等于或不等于时,值的缺少解析为 False。当解释为 Boolean 值时,Boolean 值到字符串的转换被评估为 True。第三个技巧解释了 position()
函数取决于上下文的相对特征,第四个技巧展示了如何使用 XPath preceding
轴或者谓词,来选择列表中某个给定名称的第一个元素。最后,失败 XPath select
表达式的常见问题被识别为 XML 文档中默认名称空间的结果,并给出了几个可能的解决方案。
XPath 是一种强大的用于选择 XML 文档中节点的函数式语言。但是跟所有计算机语言一样,XPath 也有学习曲线。体验这些例子,获得更深入的理解。
学习
- XSL Transformations (XSLT) Version 1.0(W3C Recommendation,1999 年 11 月):阅读这个定义 XSLT 的语法和语义的规范,XSLT 是一种用于将 XML 文档转换成其他 XML 文档的语言。
- Tip: Multi-pass XSLT: Use the node-set extension to break down the XSLT operation into two or more passes(Uche Ogbuji,developerWorks,2002 年 9 月):学习如何转换文档,以便为主要的转换做准备。
- Java 语言的 XPath API(Elliotte Rusty Harold,developerWorks,2008 年 8 月):在这篇
javax.xml.xpath
包(这是一个用于利用 XPath 查询文档的 XML 对象模型独立的库)的介绍性文章中,找到更多关于与 Java™ API 一起使用 XPath 的信息。
- Remember the difference between value1!= value2 and not(value1 = value2):在 "Ten Tips to Using XPath and XPointer" 的第四点中,查看独特逻辑的另一个例子以及另外 9 个关于 XPath 的有用技巧。
- XPath axes:从 W3schools.com 学习关于这些相对于当前节点的节点集的更多内容。
- XML 新手入门,获得学习 XML 所需的资源。
- 本作者的更多文章(Doug Domeny,developerWorks,2010 年 12 月至今):阅读关于 XSLT、XHTML 和其他技术的文章。
- developerWorks XML 专区:在 XML 专区获取提高您的专业技能所需的资源。参见 XML 技术库,获得广泛的技术文章和技巧、教程、标准和 IBM 红皮书。
- IBM XML 认证:了解如何才能成为一名 IBM 认证的 XML 和相关技术的开发人员。
- developerWorks 技术活动 和 网络广播:随时关注这些活动中的技术。
- developerWorks 播客:收听面向软件开发人员的有趣访谈和讨论。
- developerWorks 演示中心:观看演示,内容涉及面向初学者的产品安装和设置演示,以及为经验丰富的开发人员提供的高级功能。
获得产品和技术
- IBM 产品评估版:下载或 在线试用 IBM SOA Sandbox,并开始使用来自 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 的应用程序开发工具和中间件产品。
讨论
- XML 专区讨论论坛:参与任何一个 XML 相关讨论。
- 加入 developerWorks 中文社区,developerWorks 社区是一个面向全球 IT 专业人员,可以提供博客、书签、wiki、群组、联系、共享和协作等社区功能的专业社交网络社区。