1. 程式人生 > >XSLT2.0 從外部讀取資訊並分析生成對應檔案.採用xsl:for-each-group進行排序輸出

XSLT2.0 從外部讀取資訊並分析生成對應檔案.採用xsl:for-each-group進行排序輸出

解析器:Saxon

XSLT2.0相對於XSLT1.0增加了unparsed-text() collection() 函式.並且支援xsl:for-each-group來對資料進行排序.

以下程式碼主要實現的過程是:

A.使用unparsed-text()讀取外部檔案資訊.

B.使用xsl:result-document生成對應資訊的XML檔案.(使用XSLT2.0 tokenize()函式拆解捕獲資訊)

C.合併多個XML檔案.主要使用到XSLT2.0 collection()函式過濾當前資料夾中的XML檔案.

D.使用for-each-group對合並檔案中的物件進行排序重新輸出.

模擬emoplyees資訊儲存於empolyees.csv檔案中.(Format firstname,lastname,jobTitle,department)

Joe, Fawcett, Developer, IT
Max, Bialystock, CEO, Management
Phineas, Barnum, Head of Sales, Sales and Marketing
Leo, Bloom, Auditor, Accounts
Danny, Ayers, Developer, IT
Carmen, Ghia, PA to the VP of Products, Management
Ulla, Anderson, Head of Promotions, Sales and Marketing
Grace, Hopper, Developer, IT
Bob, Cratchit, Bookkeeper, Accounts
Charles, Babbage, Head of Infrastructure, IT
Roger, De Bris, VP of Products, Management
Willy, Loman, Salesman, Sales and Marketing
Franz, Liebkind, Developer, IT
Luca, Pacioli, Accountant, Accounts
Lorenzo, St. DuBois, Project Manager, IT

A.B.C三步對應的XSLT檔案如下:BuildXMLDataFromExtendFile.xslt

可在XSLT檔案中設定原始檔路徑目標合併檔案路徑.

該XSLT檔案中定義了過濾標籤內容空格函式myFunction:removeSpace

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:stylesheet version="2.0"
				xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
				xmlns:myData="http://www.ricky.com/myData"
				xmlns:xs="http://www.w3.org/2001/XMLSchema"
				xmlns:myFunction="http://www.ricky.com/myFunction"
				exclude-result-prefixes="myData myFunction xs">
<!-- 
content in empolyees.csv
dataFormat: $firstName,$lastName,$jobTitle,$department

Joe, Fawcett, Developer, IT
Max, Bialystock, CEO, Management
Phineas, Barnum, Head of Sales, Sales and Marketing
Leo, Bloom, Auditor, Accounts
Danny, Ayers, Developer, IT
Carmen, Ghia, PA to the VP of Products, Management
Ulla, Anderson, Head of Promotions, Sales and Marketing
Grace, Hopper, Developer, IT
Bob, Cratchit, Bookkeeper, Accounts
Charles, Babbage, Head of Infrastructure, IT
Roger, De Bris, VP of Products, Management
Willy, Loman, Salesman, Sales and Marketing
Franz, Liebkind, Developer, IT
Luca, Pacioli, Accountant, Accounts
Lorenzo, St. DuBois, Project Manager, IT
-->
	
	<xsl:template name="main">
		<xsl:variable name="fileLocation" select="myFunction:loadFilePath()" as="xs:string"/>
		<xsl:variable name="content" select="unparsed-text($fileLocation)"  as="xs:string"/>
		<!-- the following code save the empolyee into the separate file -->
		<xsl:for-each select="tokenize($content,'\n')">
			<xsl:call-template name="saveSeparateEmpolyee">
				<xsl:with-param name="empolyeeInfo" select="."/>
			</xsl:call-template>
		</xsl:for-each>
		<!-- the following code save all separate empolyee files into empolyees.xml(location supply by myData:targetFileLocation) -->
		<xsl:call-template name="combineAllEmpolyees">
			<xsl:with-param name="targetFile" select="myFunction:loadTargetFilePath()"/>
		</xsl:call-template>
	</xsl:template>

	<xsl:template name="saveSeparateEmpolyee">
		<xsl:param name="empolyeeInfo" as="xs:string"/>
		<xsl:variable name="firstName" select="tokenize($empolyeeInfo,',\s*')[1]" as="xs:string"/>
		<xsl:variable name="lastName" select="tokenize($empolyeeInfo,',\s*')[2]" as="xs:string"/>
		<xsl:variable name="jobTitle" select="tokenize($empolyeeInfo,',\s*')[3]" as="xs:string"/>
		<xsl:variable name="department" select="tokenize($empolyeeInfo,',\s*')[4]" as="xs:string"/>
		<!--  the value of department with 
(CR (carriage return)) -->
		<xsl:result-document href="empolyee-{myFunction:removeSpace($firstName)}-{myFunction:removeSpace($lastName)}.xml">
			<empolyee firstName="{$firstName}" lastName="{$lastName}" jobTitle="{$jobTitle}" department="{myFunction:replaceAll($department,'
','')}"/>
		</xsl:result-document>
	</xsl:template>

	<xsl:template name="combineAllEmpolyees">
		<xsl:param name="targetFile" as="xs:string"/>
		<xsl:result-document href="{$targetFile}">
			<allEmpolyees>
				<!-- load the empolyees information in separate-xml-file in current directory. format: empolyee-firstName-lastName.xml -->
				<xsl:for-each select="collection('?select=empolyee-*.xml')">
					<xsl:copy-of select="."/>
				</xsl:for-each>
			</allEmpolyees>
		</xsl:result-document>
	</xsl:template>
	
	<!-- location to save all the empolyees information -->
	<myData:targetFileLocation>
		empolyees.xml
	</myData:targetFileLocation>

	<!-- location to read the information of all the empolyees-->
	<myData:extendsFilePath>
		empolyees.csv
	</myData:extendsFilePath>

	<xsl:function name="myFunction:loadTargetFilePath" as="xs:string">
		<xsl:variable name="thisDocument" select="document('')"/>
		<xsl:variable name="result" select="myFunction:removeSpace($thisDocument/xsl:stylesheet/myData:targetFileLocation)" as="xs:string"/>
		<xsl:value-of select="$result"/>
	</xsl:function>

	<xsl:function name="myFunction:loadFilePath" as="xs:string">
		<xsl:variable name="thisDocument" select="document('')"/>
		<xsl:variable name="fileLocation" select="myFunction:removeSpace($thisDocument/xsl:stylesheet/myData:extendsFilePath)" as="xs:string"/>
		<xsl:value-of select="$fileLocation"/>
	</xsl:function>

	<xsl:function name="myFunction:removeSpace" as="xs:string">
		<xsl:param name="content" as="xs:string"/>
		<xsl:variable name="line" select="'
'" as="xs:string"/>
		<xsl:variable name="tab" select="'	'" as="xs:string"/>
		<xsl:variable name="space" select="' '" as="xs:string"/>
		<xsl:variable name="null" select="''" as="xs:string"/>

		<xsl:variable name="contentWithoutLine" select="myFunction:replaceAll($content,$line,$null)" as="xs:string"/>
		<xsl:variable name="contentWithoutTab" select="myFunction:replaceAll($contentWithoutLine,$tab,$null)" as="xs:string"/>
		<xsl:variable name="result" select="myFunction:replaceAll($contentWithoutTab,$space,$null)" as="xs:string"/>

		<xsl:value-of select="$result"/>

	</xsl:function>

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

</xsl:stylesheet>

執行命令: java net.sf.saxon.Transform -it:main -xsl:BuildXMLDataFromExtendFile.xslt 當前目錄下將生成對應每個empolyee的XML檔案及一個彙總檔案empolyees.xml(未排序)

接下來編寫empolyees.xlst檔案來對生成的未排序empolyees.xml進行重新排序

對應empolyees.xslt檔案內容如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:stylesheet version="2.0"
				xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:variable name="allEmpolyees" select="document('empolyees.xml')"/>
	<xsl:template name="main">
		<!-- Group the empolyees by @department. save as empolyees_group.xml -->
		<xsl:result-document href="empolyees_group.xml">
			<allEmpolyees>
				<xsl:for-each-group select="$allEmpolyees/allEmpolyees/empolyee" group-by="@department">
					<!-- sort by @deparment -->
					<xsl:sort select="@department" data-type="text"/>
					<department department="{current-grouping-key()}">
						<xsl:comment>
							The following show the empolyees in 
							<xsl:value-of select="current-grouping-key()"/>
						</xsl:comment>
						<xsl:apply-templates select="current-group()" mode="showDetail">
						<!-- sort by @firstName + @lastName -->
							<xsl:sort select="@firstName" data-type="text"/>
							<xsl:sort select="@lastName" data-type="text"/>
						</xsl:apply-templates>
					</department>
				</xsl:for-each-group>
			</allEmpolyees>
		</xsl:result-document>
		
	</xsl:template>

	<xsl:template match="empolyee" mode="showDetail">
		<empolyee firstName="{@firstName}" lastName="{@lastName}" jobTitle="{@jobTitle}"/>
	</xsl:template>
</xsl:stylesheet>
執行命令:java net.sf.saxon.Transform -it:main -xsl:empolyees.xslt 執行完畢後將在當前目錄下生成empolyees_group.xml檔案.

該檔案內容已經是對empolyees.xml進行排序處理後的結果.

empolyees_group.xml檔案內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<allEmpolyees>
	<department department="Accounts">
		<!--
							The following show the empolyees in 
							Accounts-->
		<empolyee firstName="Bob" lastName="Cratchit" jobTitle="Bookkeeper"/>
		<empolyee firstName="Leo" lastName="Bloom" jobTitle="Auditor"/>
		<empolyee firstName="Luca" lastName="Pacioli" jobTitle="Accountant"/>
	</department>
	<department department="IT">
		<!--
							The following show the empolyees in 
							IT-->
		<empolyee firstName="Charles" lastName="Babbage" jobTitle="Head of Infrastructure"/>
		<empolyee firstName="Danny" lastName="Ayers" jobTitle="Developer"/>
		<empolyee firstName="Franz" lastName="Liebkind" jobTitle="Developer"/>
		<empolyee firstName="Grace" lastName="Hopper" jobTitle="Developer"/>
		<empolyee firstName="Joe" lastName="Fawcett" jobTitle="Developer"/>
		<empolyee firstName="Lorenzo" lastName="St. DuBois" jobTitle="Project Manager"/>
	</department>
	<department department="Management">
		<!--
							The following show the empolyees in 
							Management-->
		<empolyee firstName="Carmen" lastName="Ghia" jobTitle="PA to the VP of Products"/>
		<empolyee firstName="Max" lastName="Bialystock" jobTitle="CEO"/>
		<empolyee firstName="Roger" lastName="De Bris" jobTitle="VP of Products"/>
	</department>
	<department department="Sales and Marketing">
		<!--
							The following show the empolyees in 
							Sales and Marketing-->
		<empolyee firstName="Phineas" lastName="Barnum" jobTitle="Head of Sales"/>
		<empolyee firstName="Ulla" lastName="Anderson" jobTitle="Head of Promotions"/>
		<empolyee firstName="Willy" lastName="Loman" jobTitle="Salesman"/>
	</department>
</allEmpolyees><strong>
</strong>