表一、運算符與特殊字符
運算符 描述/
選擇子元素,返回左側元素的直接子元素;如果"/"位於最左側表示選擇根結點的直接子元素
//
遞歸下降,不論深度,搜索指定的元素;如果位於最左側表示從根結點出發遞歸下降搜索指定元素
.
表示當前元素
*
通配符,選擇任意元素,不考慮名字
@
取得屬性值,作為屬性名的前綴
@*
通配符,選擇任意屬性,不考慮名字
:
名字作用范圍分隔符,將名字作用范圍前綴與元素或屬性名分隔開來
!*
在相關節點上應用指定方法
()*
分組,明確指定優先順序
[]
應用過濾樣式
[]*
下標運算符,用於在集合中指示元素
表二、邏輯運算符
可選方式 描述
and $and$ 或 &&
邏輯與
or $or$ 或 ||
邏輯或
not() $not$
邏輯非
表三、關系運算符
可選方式 描述
= 或 $eq$
相等
= 或 $IEq$
相等(不區分大小寫)
!= 或 $ne$
不等
$ine$
不等(不區分大小寫)
< 或 $lt$
小於
$ilt$
小於(不區分大小寫)
<= 或 $le$
小於等於
$ile$
小於等於(不區分大小寫)
> 或 $gt$
大於
$igt$
大於(不區分大小寫)
>= 或 $ge$
大於等於
$ige$
大於等於(不區分大小寫)
$all$
集合運算符,如果集合中所有項目均滿足條件則返回"真"
$any$
集合運算符,如果集合中任意項目滿足條件則返回"真"
|
集合運算符,返回兩個集合的聯合
示例一:
從個人簡歷中尋找具有具有"web開發"技能的人的姓名與E-Mail。假設文檔結構如下所示:
<document>
<resume>
<name>name</name>
<sex>sex</sex>
<birthday>birthday</birthday>
<skill>skill1</skill>
<skill>skill2</skill2>
…
<skill>skilln</skill>
</resume>
<resume>
…
</resume>
…
</document>
為從以上結構的個人簡歷中尋找出所有具有web開發"技能的人的姓名與E-Mail的XSL文檔結構如下:
<TABLE border="1" cellspacing="0">
<TH>姓名</TH><TH>E-Mail</TH>
<xsl:for-each select="resume [$any$skill="web開發"]">
<TR><TD><xsl:value-of select="name"/></TD>
<TD><xsl:value-of select="E-Mail"/></TD>
</TR>
</xsl:for-each>
</TABLE>
說明:
1.[ ] ── 表示選擇條件,只有滿足條件的個人簡歷才被顯示。
2.$any$ ── 由於每個人有多種技能,故加$any$作為前綴,以使每個人所有技能都能被比較。
3.skill='web開發' ── 篩選條件。
示例二、
仍上面的XML文檔為例,如果欲選擇1977/1/1之前出生的人的姓名、技能與E-Mail,相應的XSL文檔結構如下(假定生日格式為yyyy/mm/dd):
<TABLE border="1" cellspacing="0">
<TH>姓名</TH><TH>技能</TH><TH>E-Mail</TH>
<xsl:for-each select="resume[birthday$lt$"1977/1/1"]">
<TR>
<TD><xsl:value-of select="name"/></TD>
<TD>
<xsl:value-of select="skill[0]"/>
<xsl:for-each select="skill[index()>0]">、
<xsl:value-of select="."/>
</xsl:for-each>
</TD>
<TD><xsl:value-of select="E-Mail"/></TD>
</TR>
</xsl:for-each>
</TABLE>
說明:
1.birthday $lt$ '1977/1/1' ── 搜索條件,在此處使用"< "會錯誤,故使用"$lt$"表示小於。
2.skill [0] ── 表示選擇skill的第一項。
3.skill [index()>0] ── 表示選擇skill的第二項以後(包括第二項)的項目。
4.xsl:value-of select="." ── 表示選擇當前標記的值。
相信大家應該注意到,在前面以及本次的例子中出現了一些函數,如index()、formatIndex()、childNumber(),也許大家還不完全明了其中的含義吧?敬請關注下一課。
本期學習XSL樣式方法,即可用於XSL元素<xsl:for-each>、<xsl:value-of>、<xsl:template>的select屬性、<xsl:apply-templates>的match屬性、<xsl:if>、<xsl:when>的test屬性中,對元素的范圍進行篩選,從而提供更大的靈活性。
XML與DHtml(動態Html)一樣,這些節點都是一個個對象,而且這些對象都是有層次的,從根節點開始構成一顆層次清淅的樹狀結構,這就形成了文檔對象模型DOM(Document Object Model),通過對象的屬性、方法來達到訪問控制XML節點的目的。
我們這裡不打算就XML的DOM逐一詳細闡述,因為這完全可以寫成一個篇幅較多的教程,我們先就一些常見的方法作一些討論,以期對DOM的對象方法有一個大致的了解。
注:從本期開始,所有示例不再提供完整源代碼,如有不明白之處,請仔細閱讀前面七期、並動手練手。
一、end()
含義:返回集合中最後一個元素。
示例:輸出最後一份簡歷
假定XML文件格式為:
……<resume>…</resume>……<resume>…</resume>……
相應XSL文件內容為:
<xsl:for-each select="resume[end()]">……</xsl:for-each>
或:
<xsl:templates match="resume[end()]">……</xsl:templates>
或:
<xsl:apply-template select="resume[end()]">……</xsl:apply-template>
二、index()
含義:返回該元素在集合中的位置,返回值是一整數,其中第一個元素返回0。
示例:返回前面三份簡歷。
resume[index()$le$3]
注意:index()是與父元素相關的,請看下例:
<x>
<y/>
<y/>
</x>
<x>
<y/>
<y/>
</x>
返回所有<x>中的第一個<y>
x/y[index()=0] 或x/y[0]
三、nodeName()
含義:返回元素的名字,即標記名。
示例:選擇任意元素,假如其名字(即標記名)等於"name":
*[nodeName()='name'] 或 *[name]
四、number()
含義:將值轉換為數值形式,如果不是數值則返回空,要求參數。
示例:年齡(age)小於30歲的人的簡歷(resume):
resume[number(age)$lt$30] 或 resume[age$lt$30]
五、nodeType()
含義:返回結點類型,結果為是數值。以下是返回值列表:
結點類型 結點類型值 結點的字符形式描述 Element 1 'element' Element Attribute 2 'attribute' Markup-Delimited Region of Text 3 'text' Processing Instruction 7 'processing_instruction' Comment 8 'comment' Document Entity 9 'document'
六、value()
含義:返回元素或屬性的值。
示例:value()是元素或屬性的缺省方法,以下表示是等價:
name!value()="NAME" 與 name="NAME"
@attr="attribute_value" 與 @attr="attribute_value"
注:@是屬性前綴,@attr表示是屬性attr
七、attribute()
含義:返回所有屬性結點的集合,等價於"@*"。
示例:尋找所有的resume元素,滿足條件至少有一個屬性的值為"ABC":
resume[$any$attribute()='ABC'] 或 resume[$any$@*='ABC']
尋找所有的resume元素,滿足條件至少有一個子元素有一個屬性的值為"ABC":
resume[$any$*/attribute()='ABC'] 或 resume[$any$*/@*='ABC']
八、comment()
含義:返回所有注釋結點。
示例:
resume[$any$comment()='禹希初的簡歷']
表示尋找含有注釋語句:<!--禹希初的簡歷-->的<resume>元素。
九、cdata()
含義:返回所有CDATA類型的結點的集合。
示例:
resume[$any$cdata()='禹希初的簡歷']
表示尋找含有下述語句(必須是直接子結點)<![CDATA[禹希初的簡歷]]>的<resume>元素。
十、node()
含義:返回當前上下文環境中除根結點和屬性結點以外的所有結點的集合,等價於:
"*|pi()|comment()|text()"
示例:尋找所有元素resume,其最後一個結點的名字為"skill":
resume[node()[end()]!nodeName()='skill']
尋找所有resume元素的第一個結點:resume/node()[0]。
十一、textnode()
含義:返回所有文本類型的結點的集合。
示例:尋找每一個p元素的第二個文本結點:
p/textnode(1) 或 p!textnode(1)
十二、text()
含義:返回所有表示文本字符串的結點的集合,等價於"cdata()|textnode()"。
本期的內容就介紹至此,另有一個函數date()在本人的機器上一試就發生錯誤使浏覽器自動關閉,還有一個函數pi()本人尚未找到適當的應用方法,就不介紹了,下期將講述如何XSL中使用腳本。
有時,我們可能會希望XML文檔輸出時能對其中內容加上一些統計信息或者如編號什麼的,利用前面的知識就不太容易實現了。今天將介紹兩個新元素<xsl:eval>與<xsl:script>,使我們能輕松處理這個難題。
<xsl:eval>
含義:計算腳本表達式,輸出一個文本字符串。
語法:
<xsl:eval language="language-name">
屬性:
language ── 規定所用腳本語言的名字,可用的屬性有"JavaScript"、"JScript"、"VBScript"、"VBS"等,缺省為"JScript"。
<xsl:script>
含義:聲明全局變量或定義函數。
語法:
<xsl:script language="language-name">
屬性:同<xsl:eval>
示例:
不知大家對於第四期《跟我學XML》中的例子是否還有印象?其中的XML文檔並沒有對簡歷編號,但輸出中卻加上了大寫的羅馬數字序號。今天將再舉一稍為復雜一些的例子:
假如我們編寫一份年終生產統計表,其中需要小計一項,常規的作法是事先將其算出來,現在不必了,我們可以只給出單項統計,顯示時再統計小計一項。請找出《跟我學XML》的第四期,XML文件不必修改,對XSL文件的修改如下:
<?XML version="1.0" encoding="GB2312"?>
<xsl:stylesheet XMLns:xsl="http://www.w3.org/TR/WD-xsl">
<xsl:template match="/">
<Html><HEAD><TITLE>1999年生產統計</TITLE></HEAD>
<BODY><xsl:apply-templates select="document"/></BODY>
</Html>
</xsl:template>
<xsl:template match="document">
<H3>1999年生產統計</H3>
<TABLE border="1" cellspacing="0">
<TH>班組</TH>
<TH>一季度</TH>
<TH>二季度</TH>
<TH>三季度</TH>
<TH>四季度</TH>
<xsl:apply-templates select="report"/>
<TR><TD>小計</TD>
<TD><xsl:eval>total(this,"q1")</xsl:eval></TD>
<TD><xsl:eval>total(this,"q2")</xsl:eval></TD>
<TD><xsl:eval>total(this,"q3")</xsl:eval></TD>
<TD><xsl:eval>total(this,"q4")</xsl:eval></TD>
</TR>
</TABLE>
<xsl:script>
function total(node,q)
{
temp=0;
mark='/document/report/'+q;
v=node.selectNodes(mark);
for(t=v.nextNode();t;t=v.nextNode())
{
temp+=Number(t.text);
}
return temp; //小計值
}
</xsl:script>
</xsl:template>
<xsl:template match="report">
<TR>
<TD><xsl:value-of select="class"/></TD>
<TD><xsl:apply-templates select="q1"/></TD>
<TD><xsl:apply-templates select="q2"/></TD>
<TD><xsl:apply-templates select="q3"/></TD>
<TD><xsl:apply-templates select="q4"/></TD>
</TR>
</xsl:template>
<xsl:template match="q1|q2|q3|q4">
<!--此處測試產量,如小於等於20則添加一STYLE屬性color,其值為red(紅色)-->
<xsl:if test=".[value() $le$ 20]">
<xsl:attribute name="style">color:red</xsl:attribute>
</xsl:if>
<xsl:value-of/>
</xsl:template>
</xsl:stylesheet>
上例在浏覽器中的樣子(IE5.0或更新版本)
說明:
注意到執行結果的變化了嗎?黑體部分為添加部分,注意添加部分分為兩部分,<xsl:script></xsl:script>必須置於</TABLE>之後,切記。
selectNodes() ── 是XMLDOMObject的一個方法,返回文檔中所有滿足條件的結點的集合,條件與< xsl:for-each >和select屬性的取值采用同樣的寫法,可以加篩選、下標等限制,如尋找一季度產量大於等於50的班組:
/document/report/q1[value() $ge$ 50]
以上寫法還有一個更簡單的寫法:
//q1[value()$ge$50]
//表示從根結點出發遍歷所有結點,尋找滿足條件的結點,如果文檔內有同名但意義不同的結點則不能用此種方法,非不得已不建議使用。以此為例,如果希望統計年總產量,則可以下述字符串尋找結點(建議使用最後一種,此種描述將精確找到需要匯總的數據):
//*[value()$gt$0] 或 //(q1|q2|q3|q4) 或 /document/report/(q1|q2|q3|q4)
nextNode() ── 返回結點集中的下一個結點
Number() ── 將提供的參數轉換為數值
下期介紹XSL函數2,用於<xsl:script>及<xsl:eval>中,以及<xsl:if>和<xsl:when>的expr屬性。建議讀者熟悉JavaScript、JScript、VBScript中至少一種,否你能用XSL完成的工作將十分有限。由於篇幅關系,此處不作詳細介紹。
本期介紹多個XSL對於VBScript、JScript增加的方法、屬性,以充分發揮XML的優勢,用於<xsl:script>、<xsl:eval>標記內表達式的編寫或<xsl:if>、<xsl:when>的expr屬性。
一、absoluteChildNumber
含義:返回結點相對於它所有的兄弟(不論名字是否相同)的序號。
語法:absoluteChildNumber(node)
參數:node ── 對象,欲返回編號的結點。
示例:
1、假定文檔結構為:<document><head/><body/></document>,其中document為頂層結點,下述表達式將輸出:
<xsl:eval>
absoluteChildNumber(this.selectNodes('/document/body').item(0))
</xsl:eval>
2、確定當前結點相對於其所有兄弟的序號:
<xsl:eval>
absoluteChildNumber(this)
</xsl:eval>
二、ancestorChildNumber
含義:從給定結點出發根據給定祖先結點名返回最近的祖先結點的序號(相對於同名結點)。如果找不祖先,則返回0。
語法:ancestorChildNumber(bstrNodeName, pNode)
參數:
bstrNodeName ── 字符串。被搜索的祖先結點的名字。
pNode ── 對象。搜索開始位置的結點。
示例查找當前結點最近的名為report祖先結點:
ancestorChildNumber('report',this)
三、attributes
含義:返回結點屬性的集合。
語法:object.attributes
參數:object ── 結點對象。
示例:當前結點屬性的個數
this.attributes.length
當前結點第三個屬性的值
this.attributs.item(2).value
或
this.attributes.item(2).text
或
this.attributes(2).text
注意:如果給定的下標大於屬性總和減1將出錯,第一個屬性的下標是0。
四、baseName
含義:返回有名字空間限制的基本名,即不包括名字前綴。
語法:object.baseName
參數:object ── 結點對象
示例,當前結點的基本名:
this.baseName
五、childNumber
含義:返回結點相對於同名同胞的序號。
語法:childNumber(object)
參數:object ── 結點對象
示例,假定XML文檔結構如下:
<x><y><z></z></y></x>
如果當前結點是z,則childNumber(this)返回1,而absoluteChildNumber(this)返回3。
六、dataType
含義:設定或讀取結點的數據類型。
語法:設定結點的數據類型 object.dataType=objValue
讀取結點的數據類型 objValue=object.dataType
參數:object ── 結點對象。
示例,讀取當前結點的數據類型:
dtType=this.dataType
七、depth
含義:指定結點出現在文檔樹上的深度,即該結點位於文檔第幾層,頂層結點位於第一層,根結點(即用"/"表示的結點)位於第0層。
語法:depth(pNode)
參數:pNode ── 結點對象
示例,當前結點的深度:
depth(this)
八、firstChild、lastChild
含義:返回結點的第一個子結點(或最後一個子結點)。
語法:pNode.firstChild
pNode.lastChild
參數:pNode ── 結點對象
示例,當前結點的第一個結點的名字:
this.firstChild.nodeName
九、formatIndex
含義:用指定的計數系統格式化提供的整數。
語法:formatIndex(lIndex, bstrFormat)
參數:
lIndex ── 整型數值或變量
bstrFormat ── 數據格式,可選值有a、A、i、I、1、01(以0打頭的數值形式,如果要求固定長度的編號如0001、0002則非常有用)。
示例,當前結點的大寫羅馬數字編號:
formatIndex(childNumber(this),'I')
十、formatNumber
含義:以指定格式輸出數值。
語法:formatNumber(dblNumber, bstrFormat)
參數:說明同formatNumber,不同之處在於格式化的可以是小數。
示例,對變量a的值格式化為兩位小數:
formatNumber(a,'#.00'):
十一、hasChildNodes
含義:如果結點有子結點則返回true(-1),否則為false(0)。
語法:pNode.hasChildNodes()
注意:與此前介紹的函數不同,此函數後必須帶一個空括號。
示例,判斷當前結點是否有子結點:
this.hasChildNodes
十二、namespaceURI、prefix
含義:返回結點名字空間的全局資源標識符(或前綴)。
語法:pNode.namespaceURI
pNode.prifix
十三、nextSibling、previousSibling、parentNode
含義:返回結點的下一個兄弟(或前一個兄弟、或結點的父結點)。
語法:pNode.nextSibling
pNode.previousSibling
pNode.parentNode
注意:對根結點(即"/")應用parentNode方法、對第一個孩子結點應用previousSibling方法、對最後一個孩子結點應用nextSibling方法均會導致錯誤,可通過此過關系運算符==(等於)和!=(不等於)來判斷一個結點是否某一指定結點,格式為pNode1 = pNode2或pNode2 != pNode2。
十四、nodeName
含義:返回元素、屬性、入口的名字或其他類型結點的一個特定字符串。
語法:pNode.nodeName
示例,當前結點的名字:
this.nodeName
十五、nodeType、NodeTypeString
含義:返回結點的類型的數值形式(或字符串形式)。
語法:pNode.nodeType 或 pNode.nodeTypeString
返回值:
結點類型 結點類型值 結點的字符形式描述 Element 1 'element' Element Attribute 2 'attribute' Markup-Delimited Region of Text 3 'text' Processing Instruction 7 'processing_instruction' Comment 8 'comment' Document Entity 9 'document'
十六、nodeTypedValue
含義:以結點預定義的數據類型返回結點的值。
語法:pNode.nodeTypedValue
示例,假定當前結點的數據類型是fixed.14.4,下例將以數值返回結點的值,而不是文本一個字符串:
this.nodeTypedValue
十七、nodeValue
含義:返回結點的文本。
語法:pNode.nodeValue
注意:該方法不用於元素類結點,可用於屬性、CDATA、注釋、文本等結點。
示例,當前元素第一個屬性的值:
this.attributes(0).nodeValue
當前元素內的文本(假定該元素內只有文本,無其它元素,即<mark>text</mark>,建議多嘗幾次掌握其確切的用法)。
this.firstChild.nodeValue
十八、ownerDocument
含義:返回包含該結點的文檔的根。
語法:pNode.ownerDocument
注意:該方法用於文檔的根結點將出錯。
十九、selectNodes
含義:給定的樣式匹配應用於當前結點並返回匹配的結點集合。
語法:pNode.selectNodes('pattern')
提示:pattern的編寫與<xsl:for-each>的select屬性的值類似,其中以"/"開頭表示從文檔的根出發搜索;以"//"開頭表遍歷文檔的所有結點;以".."開頭表示從當前結點的父結點開始;如果欲從當前結點向下搜索則不能有以上特殊字符打頭。
示例,與當前結點同名的元素在其父元素內的個數:
childNumber(this.selectNodes("../"+this.nodeName+"[end()]").item(0))
當前元素內名字為"skill"的元素的個數:
childNumber(this.selectNodes("skill[end()]").item(0))
二十、selectSingleNode
含義:與selectNodes類似,不同的只返回匹配的第一個結點、而不是結點集合。
語法:pNode.selectSingleNode('pattern')
示例,與當前結點同名的元素在其父元素內的個數:
childNumber(this.selectSingleNode("../"+this.nodeName+"[end()]"))
當前元素內名字為"skill"的元素的個數:
childNumber(this.selectSingleNode("skill[end()]"))
二十一、text
含義:返回結點與它的子樹內的文字內容。
語法:pNode.text
示例,整個文檔內的文字內容:
this.ownerDocument.text
當前元素及其子樹的文字內容:
this.text
二十二、XML
含義:返回結點及其後代的XML表示。
語法:pNode.XML
示例,當前文檔的XML內容:
this.ownerDocument.XML
另有幾個函數不作介紹,列於其下以供參考,如感興趣,請訪問http://msdn.microsoft.com獲取詳細說明。
formatTime(varTime, bstrFormat,varDestLocale)
formatDate(varDate, bstrFormat,varDestLocale)
apendChild(newChild)
definition
CloneNode
insertBefore(newChild, refChild)
parsed
removeChild(oldChild)
replaceChild(newChild, oldChild)
specifIEd
transformNode(stylesheet)
transformNodeToObject(stylesheet,outputObject)
uniqueID(pNode)