<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Vincent.Chan‘s Blog

    常用鏈接

    統(tǒng)計(jì)

    積分與排名

    網(wǎng)站

    最新評(píng)論

    使用 XML: 處理指令和參數(shù)::添加多個(gè)樣式表支持

    級(jí)別: 初級(jí)

    Benoit Marchal, 顧問(wèn), Pineapplesoft

    2001 年 9 月 01 日

    這個(gè)月,我們不辭辛勞的專(zhuān)欄作家將多個(gè)樣式表的支持添加到 XM 內(nèi)容管理項(xiàng)目中。 在這樣做時(shí),他涉及到了 TrAX URIResolver 并編寫(xiě)偽屬性的解析器。如往常一樣,可在 developerWorks 開(kāi)放源碼專(zhuān)區(qū)獲得完整的源代碼。

    在“使用 XML”專(zhuān)欄文章中,Beno?t Marchal 每個(gè)月都報(bào)告其關(guān)于一個(gè)或多個(gè)開(kāi)放源碼 XML 開(kāi)發(fā)項(xiàng)目的進(jìn)展。 您可以隨著他的進(jìn)展,遵循他的設(shè)計(jì)決策和編碼選擇,也可以提出一些建議以及在您自己的項(xiàng)目中重用該開(kāi)放源代碼。

    繼續(xù)有 關(guān) XM 的工作。這個(gè)月,我已經(jīng)添加了多個(gè)樣式表支持,因此可以解決讀者發(fā)來(lái)的最常見(jiàn)建議。 我還添加了一個(gè)將一些參數(shù)傳遞到樣式表的選項(xiàng),它使 XM 基本的發(fā)布功能更完美。 在開(kāi)始繼續(xù)開(kāi)發(fā)更高級(jí)的功能期間,我已經(jīng)包括了一個(gè)目錄閱讀器。(您可以下載有關(guān)這篇文章以及以前專(zhuān)欄文章的所有相關(guān)代碼; 請(qǐng)參閱副欄 獲取代碼。)

    多個(gè)樣式表

    XM 的頭兩個(gè)版本沿用“用一種模式來(lái)套用所有”策略,最初看上去似乎是一個(gè)好主意,但經(jīng)過(guò)證實(shí)它是無(wú)效的。 更明確地講,到現(xiàn)在為止,XM 只識(shí)別一種樣式表 rules.xsl 。正如本系列的第一篇文章中說(shuō)明的那樣, 我原先認(rèn)為我本可以使用不同的 XSLT 模板來(lái)選擇樣式的變更:

    												<xsl:template match="db:article">
    <!-- rules for an article here -->
    </xsl:template>
    <xsl:template match="xm:Directory">
    <!-- rules for a directory here -->
    </xsl:template>

    然 而,我自己在 ananas.org(我完全用 XM 維護(hù)的網(wǎng)站)上的經(jīng)歷說(shuō)明了我最初的計(jì)劃不能很好地工作。 我還收到一些讀者的建議,建議我解決那些他們察覺(jué)是缺陷的問(wèn)題。最后, 當(dāng)我開(kāi)始著手內(nèi)容生成(稍后將在本文中介紹)時(shí),更覺(jué)得有必要添加多個(gè)樣式表的支持了。

    獲取代碼

    跟往常一樣, 可以從 CVS 資源庫(kù)(請(qǐng)參閱 參考資料)下載該專(zhuān)欄文章的代碼。可以從同一個(gè)地方下載 ZIP 文件。 這個(gè)月,下載文件包括樣本 .xml 和 .xsl 文件。

    處理指令

    您可能記起,易用性是我優(yōu)先使用 XM 的原因之一, 明確地講,我不希望使用配置文件或“構(gòu)建腳本”來(lái)選擇哪個(gè)樣式表適用于哪個(gè)地方(有關(guān)這一需求的完整討論, 請(qǐng)閱讀 使用 XML:將 XSLT 用于內(nèi)容管理)。

    讀者建議用巧妙的命名約定來(lái)選擇樣式表,但對(duì)于解決方案的最好提議來(lái)自一位同事, 他提醒我使用 xml-stylesheet 處理指令。

    如果您不熟悉 xml-stylesheet ,則可以看于 1999 年 7 月發(fā)表的小的 W3C 建議書(shū),其中介紹了它,xml-stylesheet 是通過(guò) Internet Explorer 5.0 而得到普及。處理指令將樣式表(XSL 或 CSS)與 XML 文檔相關(guān)聯(lián)。 例如:

    												<?xml version="1.0"?>




    <?xml-stylesheet href="classic.xsl" type="text/xml"?>
    <?xml-stylesheet href="funky.xsl" type="text/xml" alternate="yes"?>



    <article>
    <articleinfo>
    <title>ananas.org</title>
    <!-- rest of the document goes here -->


    一般而言,處理指令對(duì)應(yīng)用程序特定的數(shù)據(jù)進(jìn)行編碼。您已經(jīng)熟悉了處理指令,因?yàn)榇蠖鄶?shù) XML 文檔都是以 XML 聲明開(kāi)始, 該聲明本身就是特殊的處理指令。一條處理指令包含一個(gè)目標(biāo)(在上面示例中, xml-stylesheet ),后跟數(shù)據(jù)。 用 <??> 定界符將處理指令包起來(lái)。目標(biāo)確定應(yīng)用程序, 而對(duì)應(yīng)用程序不能識(shí)別的目標(biāo),其會(huì)忽略這些處理指令。

    數(shù)據(jù)格式完全是自由的。XML 不指定將什么東西放進(jìn)去(當(dāng)然,除了 XML 聲明)。 事實(shí)上,由于歷史原因,處理指令可以包含 PostScript 圖像或腳本等……但決不包含標(biāo)記。

    象聲明一樣, xml-stylesheet 有特殊地位,因?yàn)樗怯?W3C 定義的。 它必須出現(xiàn)在文檔的開(kāi)始(即,在第一個(gè)元素之前),并且包含幾個(gè)所謂的 偽屬性。這個(gè)數(shù)據(jù)之所以稱(chēng)為偽屬性, 是因?yàn)槠湔Z(yǔ)法與 XML 屬性相似。

    最重要的偽屬性是 href ,它包含指向樣式表的 URI。其它有用的偽屬性有 typealternatetype 是樣式表的 MIME 類(lèi)型, 它用來(lái)區(qū)別 CSS 和 XSL。如果有多個(gè) xml-stylesheet 指令, 則 alternate 表明哪一個(gè)替代主樣式表。處理器應(yīng)該用備用樣式表列表提示用戶(hù)。 然而,因?yàn)?XM 以批處理方式工作,所以它使用不同的策略,完全忽略備用樣式表。

    雖然 xml-stylesheet 是一種 W3C 標(biāo)準(zhǔn),但 TrAX 處理器忽略它,除非另行告知。 應(yīng)用程序必須明確地調(diào)用 getAssociatedStylesheet() 來(lái)檢索處理指令,如下:

    												Source document = new StreamSource(file),
    stylesheet = factory.getAssociatedStylesheet(document,null,null,null);

    if(null != stylesheet)
    transformer.transform(document,new StreamResult(System.out));
    else
    throw new XMException("Cannot find the style sheet");

    然而, getAssociatedStylesheet() 帶來(lái) XM 必須避免的兩個(gè)問(wèn)題。首先, getAssociatedStylesheet() 使高速緩存常用樣式表變得困難。其次,它假設(shè)樣式表存儲(chǔ)在與文檔相同的目錄中。 我喜歡將樣式表存儲(chǔ)在不同的目錄中,因?yàn)槲野l(fā)現(xiàn),如果樣式表都被分組在一個(gè)目錄中,可以易于維護(hù)和共享樣式表。

    還傳遞樣式表參數(shù)

    選擇樣式表僅僅完成了解決方案的一半。 通常,我希望做一些小小的變動(dòng),而不必編寫(xiě)新的樣式表。對(duì)于這種情況,我喜愛(ài)的解決方案是使用參數(shù), 如清單 1 所示:


    清單 1:樣本參數(shù)
    												<xsl:stylesheet ...>

    <xsl:param name="sponsor" select="'none'"/>

    <xsl:template match="articleinfo">




    <xsl:if test="$sponsor='dw'">


    <center>
    <a >
    <img align="middle" width="136" height="24" border="0"
    alt="developerWorks" src="!images/buttons/dw.gif"/>
    </a>
    </center>
    </xsl:if>
    <xsl:apply-templates/>
    </xsl:template>



    還有,如何傳遞這些參數(shù)?W3C 沒(méi)有提議一種機(jī)制,所以定義新的處理指令似乎也就不足為奇了。XM 可以識(shí)別 xm-xsl-paramxml-stylesheetxm-xsl-param 的語(yǔ)法與其它處理指令相似,并且使用兩個(gè)偽屬性 namevalue

    												<?xml version="1.0"?>




    <?xm-xsl-param name="sponsor" value="dw"?>


    <article>
    <articleinfo>
    <title>XM</title>



    顯而易見(jiàn),TrAX 不支持 xm-xsl-param ,但因?yàn)槲乙呀?jīng)確定 XM 需要替換 getAssociatedStylesheet() ,所以解析 xm-xsl-param 的工作不是很多。

    但這不是意味著要對(duì)文檔解析兩次嗎?一次用于處理指令,另一次是使用 XSLT 處理器。實(shí)際上, 解析兩次不會(huì)引起更多麻煩,因?yàn)樘幚碇噶畋仨毘霈F(xiàn)在文檔開(kāi)始,所以 XM 只是重新解析文檔的一小部分。

    ProcessingInstructionHandler 和 PseudoAttributeTokenizer

    ProcessingInstructionHandler 是一種 SAX ContentHandler ,它抽取 xml-stylesheetxm-xsl-param

    處理程序截取 4 個(gè)事件。 setDocumentLocator()startDocument() 用于初始化。 大多數(shù)工作都發(fā)生在 processingInstruction() 中。至于 startElement() , 它用來(lái)停止解析,因?yàn)樗鼧?biāo)記這個(gè)開(kāi)始的結(jié)束。要停止解析, startElement() 拋出一個(gè)異常。 這種作法近乎黑客所使用的手段,這是有爭(zhēng)議的;異常一般用于報(bào)告錯(cuò)誤,然而 startElement() 中沒(méi)有錯(cuò)誤,但 SAX 沒(méi)有提供更“光明正大”的解決方案來(lái)停止解析。

    雖然偽屬性的語(yǔ)法與 XML 屬性相類(lèi)似,但 SAX 解析器不對(duì)它們進(jìn)行譯碼。XM 使用它自己的解析器 PseudoAttributeTokenizer 來(lái)對(duì)偽屬性進(jìn)行譯碼。

    PseudoAttributeTokenizer 每次掃描緩沖區(qū)一個(gè)字符,查找偽屬性。 它使用一種典型的算法,這種算法可以在每本編譯器書(shū)籍中找到。 如果您不熟悉方面的內(nèi)容,那么我推薦您閱讀以 Pascal 聞名的 Niklaus Wirth 的 Compiler Construction(請(qǐng)參閱 參考資料)。

    要簡(jiǎn)化該代碼, getc() 方法返回緩沖區(qū)中的下一個(gè)字符,而 putc() 替換緩沖區(qū)中 getc() 下一次調(diào)用的字符。

    PseudoAttributeTokenizer 的公用接口由三個(gè)方法組成: hasMoreTokens() 測(cè)試緩沖區(qū)中是否還有偽屬性, nextName() 返回下一個(gè)名稱(chēng), nextValue() 返回下一個(gè)值。

    讓我們研究一下 nextName() 。它通過(guò)調(diào)用 eatSpaces() 來(lái)除去前導(dǎo)空格。接下來(lái), 只要它發(fā)現(xiàn)有數(shù)字或字母,就一直循環(huán)下去,并將字符累積在變量( token )中。因?yàn)槊Q(chēng)只包含數(shù)字和字母, 所以任何其它字符都可以表示這個(gè)循環(huán)的結(jié)束。 nextName() 特別關(guān)注讀入緩沖區(qū)的、返回的最后一個(gè)字符, 其中,它將用于 nextValue()


    清單 2:nextName() 示例
    												public String nextName()
    throws SAXParseException
    {
    token.setLength(0);
    int c = eatSpaces();
    for(;;)
    if(c == -1)
    throw new SAXParseException(UNEXPECTED_EOS,locator);
    // strictly speaking a name cannot start with a digit...
    else if(!Character.isLetterOrDigit((char)c) && c != '-')
    {
    putc(); // put it back for the next call
    return token.length() == 0 ? null : token.toString();
    }
    else
    {
    token.append((char)c);
    c = getc();
    }
    }

    nextValue()nextName() 相似,但它先識(shí)別等號(hào)字符(由 nextName() 將它留在緩沖區(qū)中)和引號(hào)字符。 nextValue() 還譯碼預(yù)先定義的實(shí)體( <> 以及類(lèi)似的)。

    有了 tokenizer,就很容易譯碼處理指令。以下代碼摘自 ProcessingInstructionHandler ,它用來(lái)識(shí)別 xml-stylesheetxm-xsl-param 的代碼與這類(lèi)似:


    清單 3:ProcessingInstructionHandler 摘錄
    												if(target.equals("xml-stylesheet"))
    {
    String href = null,
    type = null;
    boolean alternate = false;
    PseudoAttributeTokenizer tokenizer =
    new PseudoAttributeTokenizer(data,locator);
    while(tokenizer.hasMoreTokens())
    {
    String name = tokenizer.nextName(),
    value = tokenizer.nextValue();
    if(name.equals("href"))
    href = value;
    else if(name.equals("alternate"))
    alternate = value.equals("yes");
    else if(name.equals("type"))
    type = value.trim();
    // ignore the media attribute...
    }
    if(type != null && href != null && !alternate &&
    (type.equals("text/xsl") || type.equals("text/xml") ||
    type.equals("application/xml+xslt")))
    {
    this.href = href;
    params.clear();
    readParams = true;
    }
    else
    readParams = false;
    }

    請(qǐng)記住,XM 會(huì)忽略備用樣式表。W3C 建議書(shū)考慮到 HTTP,所以提供了優(yōu)先于備用樣式表的缺省樣式表。XM 使用與這相同的規(guī)則, 應(yīng)用它自己的缺省樣式表,而不考慮備用樣式表。

    TemplatesManager

    由于 XM 可使用多個(gè)樣式表, 所以對(duì)高速緩存的邏輯進(jìn)行了改進(jìn)。這是由 TemplatesManager 來(lái)負(fù)責(zé)。當(dāng) StylingMover 請(qǐng)求 Templates 對(duì)象時(shí),從高速緩存(如果該對(duì)象在其中)檢索該對(duì)象。如果該對(duì)象不在其中, 則 TemplatesManager 裝入樣式表并將其放入高速緩存。本質(zhì)上, TemplatesManager 是包含 java.util.Map 的封裝器,并包含用于返回 Transformer 對(duì)象的附加方法。

    正如前面所解釋的那樣,XM 不會(huì)將文檔和樣式表混在一起。它使用兩個(gè)目錄:文檔目錄和規(guī)則目錄。TrAX 提供 URIResolver 接口以控制 XSLT 處理器如何裝入文件。XSLT 處理器的 URIResolver 與 SAX 解析器的 EntityResolver 相似; 當(dāng)該處理器裝入已導(dǎo)入的樣式表(通過(guò) xsl:importxsl:include 元素)或文檔(通過(guò) document() 函數(shù))時(shí), 該處理器調(diào)用它的 resolve() 方法。

    TemplatesManager 使用內(nèi)部類(lèi) ReferenceResolver ,該類(lèi)從規(guī)則目錄裝入樣式表:


    清單 4:ReferenceResolver 示例
    												protected class ReferenceResolver
    implements URIResolver
    {
    protected File rulesDir;

    public ReferenceResolver(File rulesDir)
    {
    this.rulesDir = rulesDir;
    }

    public Source resolve(String href,String base)
    {
    if(href.endsWith(".xsl"))
    {
    File file = new File(rulesDir,href);
    if(file.exists())
    return new StreamSource(file);
    }
    return null;
    }
    }

    StylingMover

    當(dāng)然,我已經(jīng)把 StylingMover 改寫(xiě)成新類(lèi)。它現(xiàn)在用 ProcessingInstructionHandler 處理程序來(lái)解析文檔。 它使用處理結(jié)果來(lái)選擇樣式表并指定參數(shù),如 清單 5 所示。 特別要注意 try/catch 語(yǔ)句;因?yàn)? startElement() 使用特殊異常來(lái)停止解析,所以代碼必須識(shí)別那不是一個(gè)錯(cuò)誤。





    回頁(yè)首


    自動(dòng)生成內(nèi)容

    到目前為止, 有關(guān) XM 的工作已經(jīng)涉及了基本發(fā)布特性。雖然它們很重要,但我相信 XM 的真正價(jià)值體現(xiàn)在從一開(kāi)始我就縈繞在腦際的自動(dòng)內(nèi)容生成。 簡(jiǎn)而言之,這個(gè)想法是讓 XM 為您生成 XML 文檔。

    例如,許多網(wǎng)站都包含下載區(qū)。如果經(jīng)常更改文件列表, 則要維護(hù)一個(gè)帶總是最新列表的 XML 文檔是困難的。最好使用一種軟件來(lái)自動(dòng)生成列表。 該文檔可能類(lèi)似于清單 6。同樣可以從 SQL 數(shù)據(jù)庫(kù)、郵箱或者甚至遠(yuǎn)程網(wǎng)站生成文檔!


    清單 6:由 XM 讀取的目錄
    												<?xml version="1.0" encoding="UTF-8"?>
    <xm:Directory xmlns:xm="http://www.ananas.org/2001/XM/Walk/Directory">
    <xm:File isDirectory="false" isFile="true" isHidden="false" canRead="true"
    isMarked="false" lastModified="2001-07-07T18:21:10" canWrite="true"
    length="749">NotImplementedException.java</xm:File>
    <xm:File isDirectory="false" isFile="true" isHidden="false" canRead="true"
    isMarked="false" lastModified="2001-07-20T11:49:42" canWrite="true"
    length="6229">ContentHandlerExtractor.java</xm:File>
    <xm:File isDirectory="false" isFile="true" isHidden="false" canRead="true"
    isMarked="false" lastModified="2001-09-05T07:10:10" canWrite="true"
    length="2351">JAXPHelper.java</xm:File>
    </xm:Directory>

    上個(gè)月的專(zhuān)欄文章中介紹了 Mover ,其用于簡(jiǎn)化添加自動(dòng)內(nèi)容生成的過(guò)程。 這個(gè)月,我已經(jīng)在代碼中預(yù)先包含了目錄生成,并打算下個(gè)月再講述它。同時(shí), 如果您對(duì)此感興趣,可回顧一下 DirectoryReaderWalkHandlerWalkMover





    回頁(yè)首


    輪到您了

    目前,我正在用 XM 維護(hù)兩個(gè)網(wǎng)站:ananas.org 和一個(gè)內(nèi)部網(wǎng)。從使用 XM 而得到的實(shí)際經(jīng)驗(yàn)對(duì)于確定如何更改軟件十分有用。 歡迎您的加入,希望您下載 XM 副本,嘗試它,來(lái)構(gòu)建您自己的網(wǎng)站。 請(qǐng)?jiān)?ananas-discussion 郵件列表報(bào)告您的發(fā)現(xiàn)(請(qǐng)參閱 參考資料)。

    我已經(jīng)將 ananas.org 網(wǎng)站的代碼(.xml 文檔和 .xsl 樣式表)添加到 CVS 資源庫(kù)中, 您可以從那出發(fā)來(lái)設(shè)計(jì)您自己的網(wǎng)站。

    如果安裝了早期版本的 XM,則需要更新軟件以利用這個(gè)月的改進(jìn):將 rules.xsl 文件重命名為 default.xsl ,并將它移到 rules 目錄。 這與用于選擇樣式表的新標(biāo)準(zhǔn)匹配。





    回頁(yè)首


    參考資料

    • 您可以參閱本文在 developerWorks 全球站點(diǎn)上的 英文原文.

    • 參與本文的 論壇

    • 可以從 ananas.org下載該項(xiàng)目的代碼。在那里有到 developerWorks 上的 CVS 資源庫(kù)以及 ananas-discussion 郵件列表的鏈接。 我希望您加入列表,并就該項(xiàng)目,提出您的想法。

    • 如果想要 ZIP 文件,也可以獲得它。

    • XM 將 XalanXerces-J分別用作 XSLT 處理器和 XML 解析器。最初,IBM(和Lotus)開(kāi)發(fā)了這兩個(gè)工具,后來(lái)將代碼贈(zèng)予 Apache Foundation。

    • XML Extender for DB2與 DirectoryReader 類(lèi)似,但它用于 DB2 數(shù)據(jù)庫(kù)。它允許您將數(shù)據(jù)庫(kù)作為 XML 文檔訪問(wèn)……可以用 XSLT 來(lái)轉(zhuǎn)換 XML 文檔。

    • Niklaus Wirth 的 Compiler Construction(ISBN 0-2014-0353-6)是對(duì)解析的最好介紹之一。共 180 頁(yè),可以很快讀完。

    • 在 developerWorks XML 專(zhuān)區(qū)中查找更多的 XML 參考資料。




    回頁(yè)首


    關(guān)于作者

    Author photo

    Beno?t Marchal 是比利時(shí)納慕爾的顧問(wèn)和作家。他是 XML by ExampleApplied XML SolutionsXML and the Enterprise的作者。他是 Gamelan 的專(zhuān)欄作家。有關(guān)他最新項(xiàng)目的詳細(xì)信息,可在 marchal.com上找到。可以通過(guò) bmarchal@pineapplesoft.com與 Beno?t 聯(lián)系。

    posted on 2006-03-21 23:45 Vincent.Chen 閱讀(493) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): XML

    主站蜘蛛池模板: 亚洲一区免费视频| 一级一级一级毛片免费毛片| 中文毛片无遮挡高清免费| 成人免费一级毛片在线播放视频| 久久亚洲国产成人精品无码区| 伊人久久亚洲综合影院首页| 免费人成黄页在线观看日本| 免费不卡中文字幕在线| 亚洲AV成人噜噜无码网站| 免费国产在线视频| 亚洲国产精品激情在线观看| 亚洲日韩精品无码专区加勒比| 日本xxxx色视频在线观看免费| 亚洲色一色噜一噜噜噜| 亚洲第一成年免费网站| 在线看免费观看AV深夜影院| 亚洲国产精品无码久久一线| 成人a毛片视频免费看| 国产麻豆剧传媒精品国产免费| 亚洲精品人成电影网| a色毛片免费视频| 亚洲人AV永久一区二区三区久久| 亚洲大码熟女在线观看| 最近最新MV在线观看免费高清| 久久精品亚洲中文字幕无码麻豆| 在线视频网址免费播放| 亚洲国产av一区二区三区| 亚洲精品国产综合久久久久紧| 亚洲精品免费网站| 亚洲美免无码中文字幕在线| 午夜影院免费观看| 亚洲精品乱码久久久久久| 亚洲一区二区三区免费| 亚洲av无码乱码在线观看野外| 亚洲AV日韩AV永久无码色欲| 妞干网在线免费观看| 色偷偷女男人的天堂亚洲网| 99久久99这里只有免费费精品| 亚洲麻豆精品果冻传媒| 最近免费中文字幕大全高清大全1| 亚洲AV无码专区电影在线观看|