天天看點

基于XML-XSL的訂單存儲與拆分. xsl:function與xsl:result-document XSLT2.0

XSLT2.0新增了許多XSLT1.0不支援的功能.

xsl:function與xsl:result-document屬于其新增功能.

xsl:function主要是通過将自定義方法關聯到相對應的名稱空間,然後通過提供參數以及傳回對應結果.

xsl:result-document主要應用是通過在template或者是for-each中對于節點資訊進行輸出到獨立檔案.(常見于訂單資料的存儲以及提取)

以下的代碼模拟将一個存儲在orders.xml中的訂單資料拆分出來.主要用到了以上所說的這兩個标簽.

存儲orders.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet href="orders.xsl" target="_blank" rel="external nofollow"  type="text/xsl"?>
<!-- all order records -->
<orders date="2016-08-24" 
		copyright="®copyright by ricky"
		xmlns="http://www.ricky.com/orders"
		xmlns:item="http://www.ricky.com/orders/item"
		xmlns:consumer="http://www.ricky.com/orders/consumer"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="http://www.ricky.com/orders orders.xsd">
	
	<![CDATA[
		The following show the orders information.<2016-08-24>
	]]>

	<order no="201608240001">
		<item suk="a000214" quantity="1" stock="BeiJing">
			<item:name>
				Bikecycle
			</item:name>
			<mark>
				Giant AXT870
			</mark>
		</item>
		<item suk="b031634" quantity="2" stock="ShangHai">
			<item:name>
				BacketBall
			</item:name>
			<mark>
				<![CDATA[
					Wilson && Spalding
				]]>
			</mark>
		</item>
		<consumerInfo>
			<consumer:name>
				Ricky Lin
			</consumer:name>
			<mobileOrTel>
				<mobile>
					13988888888
				</mobile>
				<tel>
					0755-828888-3
				</tel>
				<tel>
					0755-88888888-325
				</tel>
			</mobileOrTel>
			<address>
				FuTian Area,ShenZhen City,GuangDong Province,China Mainland
			</address>
		</consumerInfo>
	</order>

<!-- order 2 -->

	<order no="201608240002">
		<item suk="c134103213" quantity="1" stock="ShenZhen">
			<item:name>
				Computer
			</item:name>
			<mark>
				IBM
			</mark>
		</item>
		<consumerInfo>
			<consumer:name>
				Jennie Lin
			</consumer:name>
			<mobileOrTel>
				<mobile>
					18888888888
				</mobile>
				<tel>
					0755-00000
				</tel>
			</mobileOrTel>
			<address>
				ShenZhen.
			</address>
		</consumerInfo>
	</order>


</orders>
           

與orders.xml對應的DTD限制.

<!ELEMENT orders (#PCDATA|order)*>
<!ATTLIST orders date CDATA #REQUIRED>
<!ATTLIST orders copyright CDATA #FIXED "®copyright by ricky">
<!ATTLIST orders xmlns CDATA "http://www.ricky.com/orders">
<!ATTLIST orders xmlns:item CDATA "http://www.ricky.com/orders/item">
<!ATTLIST orders xmlns:consumer CDATA "http://www.ricky.com/orders/consumer">
<!ATTLIST orders xmlns:xsi CDATA #REQUIRED>
<!ATTLIST orders xsi:schemaLocation CDATA #REQUIRED>
<!ELEMENT order (item+,consumerInfo)>
<!ATTLIST order no CDATA #REQUIRED>
<!ELEMENT item (item:name,mark?)>
<!ATTLIST item suk ID #REQUIRED>
<!ATTLIST item quantity CDATA #REQUIRED>
<!ATTLIST item stock (BeiJing|ShangHai|ShenZhen) #IMPLIED>
<!ELEMENT item:name (#PCDATA)>
<!ELEMENT mark (#PCDATA)>
<!ELEMENT consumerInfo (consumer:name,mobileOrTel,address)>
<!ELEMENT consumer:name (#PCDATA)>
<!ELEMENT mobileOrTel (mobile|tel)+>
<!ELEMENT address (#PCDATA)>
<!ELEMENT mobile (#PCDATA)>
<!ELEMENT tel (#PCDATA)>
           

與orders.xml對應的XSD限制

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:orders="http://www.ricky.com/orders" xmlns:item="http://www.ricky.com/orders/item" xmlns:consumer="http://www.ricky.com/orders/consumer" targetNamespace="http://www.ricky.com/orders" elementFormDefault="qualified" attributeFormDefault="unqualified">
	<import namespace="http://www.ricky.com/orders/item" schemaLocation="item.xsd"/>
	<import namespace="http://www.ricky.com/orders/consumer" schemaLocation="consumer.xsd"/>
	<element name="orders" type="orders:OrdersType"/>
	<element name="order" type="orders:OrderType"/>
	<element name="item" type="orders:ItemType"/>
	<element name="consumerInfo" type="orders:ConsumerInfoType"/>
	<!-- define orders element -->
	<complexType name="OrdersType" mixed="true">
		<sequence minOccurs="0" maxOccurs="unbounded">
			<element ref="orders:order"/>
		</sequence>
		<attribute name="date" type="date" use="required"/>
		<attribute name="copyright" type="string" use="required" fixed="®copyright by ricky"/>
	</complexType>
	<!-- define order element -->
	<complexType name="OrderType" mixed="false">
		<sequence>
			<element ref="orders:item" minOccurs="1" maxOccurs="unbounded"/>
			<element ref="orders:consumerInfo"/>
		</sequence>
		<attribute name="no" use="required">
			<simpleType>
				<restriction base="string">
					<pattern value="\d{12}"/>
				</restriction>
			</simpleType>
		</attribute>
	</complexType>
	<!-- define item element -->
	<complexType name="ItemType" mixed="false">
		<sequence>
			<element ref="item:name"/>
			<element name="mark" type="string" minOccurs="0" maxOccurs="1"/>
		</sequence>
		<attribute name="suk" type="string" use="required"/>
		<attribute name="quantity" use="required" type="nonNegativeInteger"/>
		<attribute name="stock" use="required">
			<simpleType>
				<restriction base="string">
					<enumeration value="BeiJing"/>
					<enumeration value="ShangHai"/>
					<enumeration value="ShenZhen"/>
				</restriction>
			</simpleType>
		</attribute>
	</complexType>
	<!-- define consumerInfo element -->
	<complexType name="ConsumerInfoType" mixed="false">
		<sequence>
			<element ref="consumer:name"/>
			<element name="mobileOrTel">
				<!-- define mobileOrTel element -->
				<complexType mixed="false">
					<sequence minOccurs="1" maxOccurs="unbounded">
						<choice>
							<element name="mobile">
								<simpleType>
									<union>
										<simpleType>
											<restriction base="string">
												<pattern value="\s*([+]?\d+\s+)?1\d{10}\s*"/>
											</restriction>
										</simpleType>
										<simpleType>
											<restriction base="string">
												<enumeration value="Unknow"/>
											</restriction>
										</simpleType>
										<simpleType>
											<restriction base="string">
												<pattern value="\s*Unknow\s*"/>
											</restriction>
										</simpleType>
									</union>
								</simpleType>
							</element>
							<element name="tel">
								<simpleType>
									<union>
										<simpleType>
											<restriction base="string">
												<pattern value="\s*([+]?\d+\s+)?\d+(-\d+){0,2}\s*"/>
											</restriction>
										</simpleType>
										<simpleType>
											<restriction base="string">
												<enumeration value="Unknow"/>
											</restriction>
										</simpleType>
										<simpleType>
											<restriction base="string">
												<pattern value="\s*Unknow\s*"/>
											</restriction>
										</simpleType>
									</union>
								</simpleType>
							</element>
						</choice>
					</sequence>
				</complexType>
			</element>
			<element name="address" type="string"/>
		</sequence>
	</complexType>
</schema>
           

名稱空間http://www.ricky.com/orders/item限制

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
		targetNamespace="http://www.ricky.com/orders/item"
		xmlns:item="http://www.ricky.com/orders/item"
		elementFormDefault="qualified"
		attributeFormDefault="unqualified">
	<element name="name" type="string"/>
</schema>
           

名稱空間http://www.ricky.com/orders/consumer限制

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
		targetNamespace="http://www.ricky.com/orders/consumer"
		xmlns:consumer="http://www.ricky.com/orders/consumer"
		elementFormDefault="qualified"
		attributeFormDefault="unqualified">
	<element name="name" type="string"/>
</schema>
           

對應的xslt檔案

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:stylesheet version="2.0"
				xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
				xmlns:xs="http://www.w3.org/2001/XMLSchema"
				xmlns:orders="http://www.ricky.com/orders"
				xmlns:item="http://www.ricky.com/orders/item"
				xmlns:consumer="http://www.ricky.com/orders/consumer"
				xmlns:myFunction="http://www.ricky.com/myFunction"
				xmlns:myData="http://www.ricky.com/myData"
				exclude-result-prefixes="xs orders item consumer myFunction myData">
	<xsl:variable name="thisDocument" select="document('')"/>
	<xsl:variable name="ordersData" select="document('orders.xml')"/>
	<xsl:template match="/">
		<html>
			<head>
				<title>
					<xsl:value-of select="$ordersData/orders:orders/text()[1]"/>
				</title>
			</head>
			<body>
				<h3>
					<xsl:value-of select="$ordersData/orders:orders/text()[1]"/>
				</h3>
				<hr/>
				<xsl:apply-templates select="$ordersData/orders:orders/orders:order" mode="menu">
					<xsl:sort select="@no" data-type="number"/>
				</xsl:apply-templates>
				<hr/>
				<table>
					<thead>
						<th>
							OrderNo
						</th>
						<th>
							ItemDetail
						</th>
						<th>
							consumerInfo
						</th>
						<th>
							Address
						</th>
					</thead>
					<tbody>
						<xsl:apply-templates select="$ordersData/orders:orders/orders:order" mode="separateSave"/>
						<xsl:apply-templates select="$ordersData/orders:orders/orders:order" mode="showDetail"/>
					</tbody>
				</table>
			</body>
		</html>
	</xsl:template>

	<xsl:template match="orders:order" mode="menu">
		<a href="#order{@no}" target="_blank" rel="external nofollow" >
			<xsl:value-of select="@no"/>
		</a>
		<<xsl:value-of select="orders:consumerInfo/consumer:name"/>>
		<br/>
	</xsl:template>
	<xsl:template match="orders:order" mode="separateSave">
		<!-- remove tab -->
		<xsl:variable name="consumerNameWithoutTab" select="myFunction:replaceAll(orders:consumerInfo/consumer:name,'
')"/>
		<!-- remove line feed-->
		<xsl:variable name="consumerNameWithoutLine" select="myFunction:replaceAll($consumerNameWithoutTab,'	')"/>
		<!-- remove space -->
		<xsl:variable name="consumerName" select="myFunction:replaceAll($consumerNameWithoutLine,' ')"/>
		<!-- ouput file name: orderNo-consumerName.html -->
		<xsl:result-document href="{concat(@no,'-',$consumerName)}.html" target="_blank" rel="external nofollow" >
			<html>
				<head>
					<title>
						<xsl:value-of select="concat('Order-',@no,' Information')"/>
					</title>
				</head>
				<body>
					<h3>
						<xsl:value-of select="myFunction:formatDate(../@date)"/>:<xsl:value-of select="@no"/>
					</h3>
					<hr/>
					consumerInfo:<xsl:apply-templates select="orders:consumerInfo"/>
					<hr/>
					<table>
						<thead>
							<th>
								ItemName
							</th>
							<th>
								SUK
							</th>
							<th>
								Quantity
							</th>
							<th>
								Stock
							</th>
							<th>
								Mark
							</th>
						</thead>
						<tbody>
							<xsl:apply-templates select="orders:item" mode="signalShow">
								<xsl:sort select="@stock" data-type="text"/>
							</xsl:apply-templates>
						</tbody>
					</table>
				</body>
			</html>
		</xsl:result-document>
	</xsl:template>

	<xsl:template match="orders:item" mode="signalShow">
		<tr>
			<td>
				<xsl:value-of select="item:name"/>
			</td>
			<td>
				<xsl:value-of select="@suk"/>
			</td>
			<td>
				<center>
					<xsl:value-of select="@quantity"/>
				</center>
			</td>
			<td>
				<xsl:value-of select="@stock"/>
			</td>
			<td>
				<xsl:value-of select="orders:mark"/>
			</td>
		</tr>
	</xsl:template>

	<xsl:template match="orders:order" mode="showDetail">
		<xsl:apply-templates select="orders:item"/>
	</xsl:template>

	<xsl:template match="orders:item">
		<tr>
			<td>
				<xsl:if test="position() = 1">
					<a name="order{../@no}">
						<xsl:value-of select="../@no"/>
					</a>
				</xsl:if>
			</td>
			<td>
				<xsl:apply-templates select="." mode="showItem"/>
			</td>
			<td>
				<xsl:if test="position() = 1">
					<xsl:apply-templates select="../orders:consumerInfo"/>
				</xsl:if>
			</td>
			<td>
				<xsl:if test="position() = 1">
					<xsl:value-of select="../orders:consumerInfo/orders:address"/>
				</xsl:if>
			</td>
		</tr>
	</xsl:template>

	<xsl:template match="orders:item" mode="showItem">
		<strong>
			<xsl:value-of select="item:name"/>
		</strong>
		<xsl:call-template name="showAttributes">
			<xsl:with-param name="attrs" select="@*"/>
		</xsl:call-template>
	</xsl:template>

	<xsl:template match="orders:consumerInfo">
		<strong>
			<xsl:value-of select="consumer:name"/>
		</strong>
		[
			<xsl:for-each select="orders:mobileOrTel/*">
				<xsl:variable name="fontColor">
					<xsl:choose>
						<xsl:when test="position() mod 2 = 0">red</xsl:when>
						<xsl:otherwise>black</xsl:otherwise>
					</xsl:choose>
				</xsl:variable>
				<font color="{$fontColor}">
					<xsl:value-of select="."/>
				</font>
				<xsl:if test="position() != last()">
					,
				</xsl:if>
			</xsl:for-each>
		]
	</xsl:template>

	<xsl:template name="showAttributes">
		<xsl:param name="attrs"/>
		<xsl:if test="count($attrs) > 0">
			[
			<xsl:for-each select="$attrs">
				<xsl:variable name="fontColor">
					<xsl:choose>
						<xsl:when test="position() mod 2 = 0">red</xsl:when>
						<xsl:otherwise>blue</xsl:otherwise>
					</xsl:choose>
				</xsl:variable>
				<font color="{$fontColor}">
					<xsl:value-of select="concat(name(),':',.)"/>
				</font>
			</xsl:for-each>
			<xsl:if test="position() != last()">
			,
			</xsl:if>
			]
		</xsl:if>
	</xsl:template>

	<xsl:function name="myFunction:replaceAll" as="xs:string">
		<xsl:param name="content" as="xs:string"/>
		<xsl:param name="replace" as="xs:string"/>
		<xsl:choose>
			<xsl:when test="contains($content,$replace)">
				<xsl:variable name="before" select="substring-before($content,$replace)"/>
				<xsl:variable name="after" select="substring-after($content,$replace)"/>
				<xsl:variable name="newContent" select="concat($before,$after)"/>
				<xsl:value-of select="myFunction:replaceAll($newContent,$replace)"/>
			</xsl:when>
			<xsl:otherwise>
				<xsl:value-of select="$content"/>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>

	
	<xsl:function name="myFunction:formatDate" as="xs:string">
		<xsl:param name="iso8601Date" as="xs:date"/>
		<xsl:variable name="yearPart" select="year-from-date($iso8601Date)" as="xs:integer"/>
		<xsl:variable name="monthPart" select="month-from-date($iso8601Date)" as="xs:integer"/>
		<xsl:variable name="datePart" select="day-from-date($iso8601Date)" as="xs:integer"/>
		<xsl:variable name="monthName" select="$thisDocument/xsl:stylesheet/myData:months/month[number(@index) = number($monthPart)]" as="xs:string"/>
		<xsl:value-of select="concat($datePart,' ',$monthName,' ',$yearPart)"/>
	</xsl:function>
	
	<!-- define month names -->
	<myData:months>
		<month index="1">January</month>
		<month index="2">February</month>
		<month index="3">March</month>
		<month index="4">April</month>
		<month index="5">May</month>
		<month index="6">June</month>
		<month index="7">July</month>
		<month index="8">Auguest</month>
		<month index="9">September</month>
		<month index="10">October</month>
		<month index="11">November</month>
		<month index="12">December</month>
	</myData:months>

</xsl:stylesheet>
           
上一篇: Music21-Chapter2
下一篇: sort()和qsort()