vb xslt2.0的
随着针对XSLT 2.0语言的W3C规范的发布,XSLT语言中引入了最重要的创新之一:XSLT处理器能够将XML模式用于输入和输出文档以及临时树和构造的能力期望指定类型,例如函数和模板参数以及变量。
模式意识是XSLT处理器要实现的一项可选功能。 一种不实现模式感知功能的XSLT处理器被称为基本XSLT处理器 ,而一个实现此类功能的XSLT处理器则被称为模式感知XSLT处理器 。
本文假定您具有XML和W3C XML Schema语言的知识,最好是具有XSLT的知识。 为了有效利用XSLT样式表中的模式感知功能,您需要详细了解XML Schema的语法和语义。 要尝试本文中的示例,您需要一个XSLT 2.0处理器,该处理器实现XSLT 2.0语言的模式感知功能。 出于本文的目的,我使用了商品Saxon-SA的评估版。 您可以下载30天免费评估版试用版功能; 有关详细信息,请参见参考资料 。
XML模式概述
XML文档可以是独立的,也可以设计为与架构相对应。 一个独立的XML文档仅包含带有文本的嵌套标签,并且仅服从XML的格式正确的约束。 另一方面,为XML模式设计的XML文档遵守该模式的约束。 几乎所有使用XML的现代应用程序都包含定义良好的XML模式。 XML模式将结构分配给XML文档,并定义元素和属性的数据类型。
与以前的XML验证语言文档类型定义(DTD)相比,W3C XML Schema语言得到了大大增强。 与XML模式(尤其是功能强大的数据键入工具)不同,DTD无法表达复杂的XML验证约束。 XML Schema语言的详细信息超出了本文的范围,但是您可以参考参考资料了解更多信息。
为什么要编写可识别架构的样式表?
模式通常可用于著名的XML词汇表和其他大型应用程序。 但是,作为样式表编写者,您可以自己维护模式和类型。 这样,您可以从应用程序体系结构和应用程序要解决的业务问题中受益匪浅。
您可以通过三种方式将XML模式放入可识别模式的XSLT环境中:
- 验证输入 XML文档 :当您使用XML模式验证输入XML文档时,XSLT模式子系统将类型注释附加到输入文档的节点上。 这允许在XSLT样式表中的节点上执行类型识别操作。 输入验证还可以确保XSLT样式表不会处理无效的输入。
- 验证输出 XML文档 :从整体应用程序体系结构的角度来看,这是可识别模式的XSLT样式表设计的最大优点之一。 通过在将XML流的控制权移交给其他正向流程之前验证XSLT转换的输出,您可以及早发现许多错误,并避免以后在处理链中出错。
- 从模式中将元素 ,属性和类型信息导入XSLT样式表 :使用样式表中的模式组件可以增强类型检查。 例如,您可以定义要内置的变量的数据类型或用户定义的模式类型。 同样,您可以为XSLT函数的输入和输出参数以及XSLT模板参数定义类型。
您可以在样式表的编译期间或运行时(即在转换输入XML文档时)使用XML模式。 XSLT 2.0规范没有提及模式的编译时用法,但是计算机语言理论使人们知道,在编译时拥有额外的类型信息可以使编译器进行编译时优化,例如生成高效代码。 还值得注意的是,您可以在XSLT样式表中内联编写模式(稍后将提供一个示例)。 这对于小型应用程序或在转换过程中验证临时树很有用。
以下示例说明了样式表在样式表中的三种用法, 如前所述 。
验证输入的XML文档
第一个示例演示了如何在XSLT样式表中利用输入文档验证。 清单1显示了一个名为po.xml的XML文档,该文档表示采购订单。
清单1. po.xml
<?xml version="1.0" encoding="UTF-8"?>
<PurchaseOrder orderid="10010"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="po1.xsd">
<orderFrom>XYZ Ltd.</orderFrom>
<shipAddress>
<name>XYZ Ltd.</name>
<address>123, Wisconsin Street</address>
<city>London</city>
<country>United Kingdom</country>
</shipAddress>
<billAddress>
<name>XYZ Ltd.</name>
<address>123, Wisconsin Street</address>
<city>London</city>
<country>United Kingdom</country>
</billAddress>
<item id="100" type="book">
<title>Water for Elephants</title>
<note>Author(s): Sara Gruen</note>
<quantity>1</quantity>
<price>18.34</price>
</item>
<item id="101" type="book">
<title>Glass Castle: A Memoir</title>
<note>Author(s): Jeannette Walls and Julia Gibson</note>
<quantity>1</quantity>
<price>23.09</price>
</item>
<item id="200">
<title>5 Amp Electric plug</title>
<quantity>5</quantity>
<price>10.10</price>
</item>
</PurchaseOrder>
清单2显示了此文档的XML模式(名为po1.xsd)。
清单2. po1.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="PurchaseOrder">
<xs:complexType>
<xs:sequence>
<xs:element name="orderFrom" type="xs:string"/>
<xs:element name="shipAddress">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="billAddress">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="note" type="xs:string" minOccurs="0"/>
<xs:element name="quantity" type="xs:positiveInteger"/>
<xs:element name="price" type="xs:decimal"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="required"/>
<xs:attribute name="type" type="xs:string" use="optional"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="orderid" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
这个架构没有什么复杂的。 您需要了解XML模式语法才能理解此示例。
现在,编写一个简单的XSLT 2.0样式表,该样式表利用清单2中的模式并处理清单1中的XML。 清单3显示了样式表的代码,该代码名为printitems1.xsl。
清单3. printitems1.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text" />
<xsl:import-schema schema-location="po1.xsd" />
<xsl:template match="document-node(schema-element(PurchaseOrder))">
<xsl:for-each select="PurchaseOrder/item">
<xsl:value-of select="@id" />: <xsl:value-of select="title" />
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
<xsl:template match="document-node()">
<xsl:message terminate="yes">Source document is not a purchase order
</xsl:message>
</xsl:template>
</xsl:stylesheet>
使用Saxon-SA产品,按如下所示调用XSLT流程:
java com.saxonica.Transform po.xml printitems1.xsl
这将产生以下输出:
Source document is not a purchase order
Processing terminated by xsl:message at line 16 in printitems1.xsl
在这种情况下,将调用清单3中的第二个模板,因为未验证输入文档。
现在按如下所示调用XSLT转换:
java com.saxonica.Transform -val:strict po.xml printitems1.xsl
这将产生以下输出:
100: Water for Elephants
101: Glass Castle: A Memoir
200: 5 Amp Electric plug
在这种情况下,将调用清单3中的第一个模板,因为已使用相应的模式验证了输入文档。
此样式表说明了以下想法:只有在输入文档已使用所需的模式进行验证的情况下,才可以在样式表中执行有用的处理。 如果未验证XML文档,则样式表将不会做任何有用的事情,如第一个输出所示。
验证输出XML文档
下一个示例演示了如何在序列化之前请求验证输出树。 清单4显示了一个名为printitems2.xsl的样式表。
清单4. printitems2.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.0">
<xsl:output method="xml" indent="yes" />
<xsl:import-schema>
<xs:schema>
<xs:element name="items">
<xs:complexType>
<xs:sequence>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="note" type="xs:string" minOccurs="0"/>
<xs:element name="quantity" type="xs:positiveInteger"/>
<xs:element name="price" type="xs:decimal"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="required"/>
<xs:attribute name="type" type="xs:string" use="optional"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</xsl:import-schema>
<xsl:template match="/PurchaseOrder">
<items xsl:validation="strict">
<xsl:copy-of select="item[price < 15]" />
</items>
</xsl:template>
</xsl:stylesheet>
请注意, <items>
标记上的xsl:validation="strict"
选项使<items>
元素在从转换生成时得到验证。
如下调用XSLT流程(输入XML保持不变):
java com.saxonica.Transform po.xml printitems2.xsl
产生以下输出:
<?xml version="1.0" encoding="UTF-8"?>
<items xmlns:xs="http://www.w3.org/2001/XMLSchema">
<item xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="200">
<title>5 Amp Electric plug</title>
<quantity>5</quantity>
<price>10.10</price>
</item>
</items>
这是预期的输出。
假设您要修改样式表的一部分,如下所示:
<xsl:template match="/PurchaseOrder">
<itemsTag xsl:validation="strict">
<xsl:copy-of select="item[price < 15]" />
</itemsTag>
</xsl:template>
请注意,您已经将根元素名称从'items'
为'itemsTag'
。 运行与前面所示相同的命令行,将产生以下输出:
Error on line 32 of file:/E:/xml/sa-xslt/printitems2.xsl:
XTTE1512: There is no global element declaration for itemsTag,
so strict validation will fail
Failed to compile stylesheet. 1 error detected.
转换期间会发生此错误,因为使用内联架构对输出树的验证未成功。 如所示,您不能从XSLT转换中产生无效的输出。
遵循清单5中的另一个有趣的示例来验证输出XML树。 本示例说明了如何请求使用不同的模式验证输出树的不同部分。
清单5. outputval.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" indent="yes" />
<!-- import 1st schema -->
<xsl:import-schema>
<xs:schema>
<xs:element name="x">
<xs:complexType>
<xs:sequence>
<xs:element name="y" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</xsl:import-schema>
<!-- import 2nd schema -->
<xsl:import-schema>
<xs:schema>
<xs:element name="p">
<xs:complexType>
<xs:sequence>
<xs:element name="q" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</xsl:import-schema>
<xsl:template match="/">
<xsl:variable name="temp1">
<x>
<y/>
</x>
</xsl:variable>
<xsl:variable name="temp2">
<p>
<q/>
</p>
</xsl:variable>
<result>
<xsl:copy-of select="$temp1" validation="strict" />
<xsl:copy-of select="$temp2" validation="strict" />
</result>
</xsl:template>
</xsl:stylesheet>
现在按如下所示调用XSLT转换:
java com.saxonica.Transform outputval.xsl outputval.xsl
请注意,在此命令行中,您将样式表本身用作输入XML。 在这里,样式表充当虚拟输入XML。
上面的命令行产生以下输出:
<?xml version="1.0" encoding="UTF-8"?>
<result>
<x>
<y/>
</x>
<p>
<q/>
</p>
</result>
这是预期的输出。 这里没有发生任何错误,因为对树片段的验证( 清单5中以粗体显示)已成功完成,而两个内联模式都没有问题。
现在,如下更改根模板(xsl:template match =“ /”):
<xsl:template match="/">
<xsl:variable name="temp1">
<x>
<something/>
</x>
</xsl:variable>
<xsl:variable name="temp2">
<p>
<q/>
</p>
</xsl:variable>
<result>
<xsl:copy-of select="$temp1" validation="strict" />
<xsl:copy-of select="$temp2" validation="strict" />
</result>
</xsl:template>
您引入了一个垃圾标记<something />,对于两个内联模式中的任何一个而言,该标记均无效(来自清单5 )。
现在运行清单5的样式表,其中根模板如上所述进行更改(命令行保持不变)。
转换产生的输出现在是:
Validation error on line 47 of file:/E:/xml/sa-xslt/outputval.xsl:
XTTE1510: In content of element <x>: The content model does not allow element
<something>
to appear here. Expected: y (See http://www.w3.org/TR/xmlschema-1/#cvc-complex
-type clause 2.4)
Transformation failed: Run-time errors were reported
由于您在生成的标记中引入了验证错误,因此转换未成功。 此示例说明XSLT 2.0非常灵活,您希望在其中进行输出树中的验证。
从架构导入类型信息
现在来看另一个示例,该示例使用模式定义的用户类型作为函数参数。 这是一个功能强大的概念,它说明您可以无限制地扩展XSLT的类型系统。 清单6显示了名为po2.xsd的模式。
清单6. po2.xsd
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="PurchaseOrder" type="POType" />
<xs:complexType name="POType">
<xs:sequence>
<xs:element name="orderFrom" type="xs:string"/>
<xs:element name="shipAddress">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="billAddress">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="note" type="xs:string" minOccurs="0"/>
<xs:element name="quantity" type="xs:positiveInteger"/>
<xs:element name="price" type="xs:decimal"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="required"/>
<xs:attribute name="type" type="xs:string" use="optional"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="orderid" type="xs:string" use="required"/>
</xs:complexType>
</xs:schema>
该模式与清单2中的 po1.xsd并没有太大不同。 唯一的区别是,它明确地命名了POType
类型,而不是在模式中匿名使用它。 您将在function参数中使用此类型名称。
现在尝试运行ordersummary.xsl样式表,该样式表使用清单6中的po2.xsd模式。 清单7中的此样式表显示了示例XML所代表的采购订单的订单摘要(作为XHTML)。
清单7. ordersummary.xsl
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="http://localhost/myfunctions"
exclude-result-prefixes="xs my"
version="2.0">
<xsl:output method="xhtml" />
<xsl:import-schema schema-location="po2.xsd" />
<xsl:import-schema namespace="http://www.w3.org/1999/xhtml"
schema-location="http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd"/>
<xsl:template match="/PurchaseOrder">
<html xmlns="http://www.w3.org/1999/xhtml" xsl:validation="strict">
<head>
<title>Order Summary</title>
</head>
<body>
<h2>Order from: <xsl:value-of select="orderFrom" /></h2>
<table>
<tr>
<td>Item type</td>
<td>Total for the item type</td>
</tr>
<xsl:for-each-group select="item" group-by="if (@type) then @type
else 'uncategorized item'">
<tr>
<td>
<xsl:value-of select="current-grouping-key()" />
</td>
<td>
<xsl:value-of select="my:categoryTotal(..,
current-grouping-key())" />
</td>
</tr>
</xsl:for-each-group>
</table>
Total amount for the order: <xsl:value-of select="my:orderTotal(.)" />
</body>
</html>
</xsl:template>
<!-- function to find order amount for a particular category of items -->
<xsl:function name="my:categoryTotal" as="xs:decimal">
<xsl:param name="po" as="element(*, POType)" />
<xsl:param name="category" as="xs:string" />
<xsl:choose>
<xsl:when test="not($category = 'uncategorized item')">
<xsl:sequence select="sum($po/item[@type = $category]/price)" />
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="sum($po/item[not(@type)]/price)" />
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<!-- function to find total order amount -->
<xsl:function name="my:orderTotal" as="xs:decimal">
<xsl:param name="po" as="element(*, POType)" />
<xsl:sequence select="sum($po/item/price)" />
</xsl:function>
</xsl:stylesheet>
现在按如下所示调用XSLT转换:
java com.saxonica.Transform po.xml ordersummary.xsl
这将产生以下输出:
Error on line 32 of file:/E:/xml/sa-xslt/ordersummary.xsl:
XPTY0004: Required item type of first argument of my:categoryTotal() is element(*,
POType); supplied value has item type element(PurchaseOrder, xs:anyType)
In template at line 14 in file:/E:/xml/sa-xslt/ordersummary.xsl
尝试了解此错误的含义以及解决方法。 因为您没有验证输入的XML文档,所以没有将正确的类型注释附加到XML节点。 结果,元素节点具有xs:anyType
类型。 发生错误是因为my:categoryTotal
函数期望POType
类型的参数值。
运行转换,如下所示:
java com.saxonica.Transform -val:strict po.xml ordersummary.xsl
请注意,您在命令行上添加了-val:strict
选项。 这次,您将获得正确的输出,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Order Summary</title>
</head>
<body>
<h2>Order from: XYZ Ltd.</h2>
<table>
<tr>
<td colspan="1" rowspan="1">Item type</td>
<td colspan="1" rowspan="1">Total for the item type</td>
</tr>
<tr>
<td colspan="1" rowspan="1">book</td>
<td colspan="1" rowspan="1">41.43</td>
</tr>
<tr>
<td colspan="1" rowspan="1">uncategorized item</td>
<td colspan="1" rowspan="1">10.1</td>
</tr>
</table>
Total amount for the order: 51.53
</body>
</html>
在此示例中考虑这些有趣的观点。
- 首先,由于输入文档已经过验证,因此该函数获得了具有正确类型的参数。
- 其次,在样式表中添加
<html xmlns="http://www.w3.org/1999/xhtml" xsl:validation="strict">
导致针对XHTML架构验证XHTML输出(其位置由指令schema-location="http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd"
)。 - 最后,尝试在输出XHTML语法中引入一些错误,然后您将看到使用XHTML架构的验证将失败。 请注意,XSLT处理器从Web上获取模式,因此计算机应连接到Internet。
摘要
本文演示了可识别架构的XSLT系统的功能。 使XSLT样式表具有架构意识可以带来以下好处:
- 您可以通过验证输入树并将类型注释附加到XML节点,在节点上执行类型识别操作。 这还可以确保样式表不会处理无效的输入。
- 您可以使用特定的模式验证输出树,从而确保您不会从XSLT转换中产生无效的输出。
- 您可以将类型分配给XSLT变量,函数/模板参数和返回值。 这提供了增强的静态类型,这在样式表的编译阶段很有用。
- 增强的编译时类型检查减少了以后出现错误的可能性。 越早发现错误,所需的时间就越少。
- 在样式表中提供用户定义的模式类型可以使XSLT的类型系统无限扩展。 结果,样式表更接近于解决业务问题。
翻译自: https://www.ibm.com/developerworks/xml/library/x-schemaxslt/index.html
vb xslt2.0的