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

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

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

    隨筆-72  評(píng)論-63  文章-0  trackbacks-0

    我們知道校驗(yàn)XML文件的方式有XSD?和XDR兩種方式,這兩種方式是利用XML?Schema來實(shí)現(xiàn)的,現(xiàn)在我們介紹另外的一種校驗(yàn):DTD。?DTD(Document?type?definition)?校驗(yàn)是使用W3C中有效性約束來實(shí)現(xiàn)的。DTD使用一種正式的文法來描述相適應(yīng)的XML文檔的結(jié)構(gòu)和語法。完成一個(gè)DTD校驗(yàn),是利用XmlValidatingReader類。XmlValidatingReader類將DTD定義在DOCTYPE中。這個(gè)DOCTYPE定義的可以包括在線的DTD或是指向一個(gè)DTD文件。

    在什么情況下使用DTD校驗(yàn)?zāi)兀渴褂肈TD校驗(yàn),可以使一個(gè)用戶組中獨(dú)立的不同的用戶使用共同的DTD來交換數(shù)據(jù)。比如,你可以使用共同的DTD校驗(yàn)?zāi)闼邮艿降腦ML數(shù)據(jù)是不是有效,你也可以用DTD來校驗(yàn)?zāi)阕约旱臄?shù)據(jù)。

    下面我們用一個(gè)例子來說明DTD是如何使用的。

    首先寫一個(gè)HeadCount.dtd:

    <!ELEMENT?HeadCount?(Name)*>//ELEMENT說明元素是HeadCount

    <!ELEMENT?Name?(Name)*>?//ELEMENT說明元素是Name


    <!ATTLIST?Name?First?CDATA?#REQUIRED>//ATTLIST說明元素Name后面是屬性First

    <!ATTLIST?Name?Last?CDATA?#REQUIRED>//ATTLIST說明元素Name后面還有一個(gè)是屬性Last


    <!ATTLIST?Name?Relation?(self?|?spouse?|?child)?"self">

    <!ENTITY?MyFirst?"Jeff">

    <!ENTITY?MyLast?"Smith">


    具體的DTD規(guī)范可以參考W3C規(guī)范。

    還有一個(gè)待校驗(yàn)的XML文件HeadCount.xml:

    <!DOCTYPE?HeadCount?SYSTEM?"HeadCount.dtd">

    <HeadCount>

    <Name?First="Waldo"?Last="Pepper">

    <Name?First="Salt"?Last="Pepper"?Relation="spouse"/>

    <Name?First="Red"?Last="Pepper"?Relation="child"/>

    </Name>

    <Name?First="&MyFirst;"?Last="&MyLast;">

    <Name?First="Sharon"?Last="&MyLast;"?Relation="spouse"/>

    <Name?First="Morgan"?Last="&MyLast;"?Relation="child"/>

    <Name?First="Shelby"?Last="&MyLast;"?Relation="child"/>

    </Name>

    </HeadCount>


    現(xiàn)在我們寫一個(gè)cs文件來實(shí)現(xiàn)校驗(yàn):

    testDtd.cs

    using?System;

    using?System.IO;

    using?System.Xml;

    using?System.Xml.Schema;


    class?testDtd

    {

    public?static?void?Main()

    {

    XmlTextReader?tr?=?new?XmlTextReader("HeadCount.xml");

    XmlValidatingReader?vr?=?new?XmlValidatingReader(tr);


    vr.ValidationType?=?ValidationType.DTD;

    vr.ValidationEventHandler?+=?new?ValidationEventHandler?(ValidationHandler);


    while(vr.Read());

    Console.WriteLine("Validation?finished");

    }


    public?static?void?ValidationHandler(object?sender,?ValidationEventArgs?args)

    {

    Console.WriteLine("***Validation?error");

    Console.WriteLine("\tSeverity:{0}",?args.Severity);

    Console.WriteLine("\tMessage?:{0}",?args.Message);

    }

    }


    運(yùn)行這個(gè)程序,可以發(fā)現(xiàn)校驗(yàn)正確。

    但如果我們把它改下呢?

    我們將HeadCount.dtd改成:

    <!ELEMENT?HeadCount1?(Name)*>

    <!ELEMENT?Name?(Name)*>

    <!ATTLIST?Name?First?CDATA?#REQUIRED>

    <!ATTLIST?Name?Last?CDATA?#REQUIRED>

    <!ATTLIST?Name?Relation?(self?|?spouse?|?child)?"self">

    <!ENTITY?MyFirst?"Jeff">

    <!ENTITY?MyLast?"Smith">


    既將第一個(gè)元素改成HeadCount1,再運(yùn)行這個(gè)程序,結(jié)果如下:


    ***Validation?error

    Severity:Error

    Message?:The?'HeadCount'?element?is?not?declared.?An?error?occurred?at

    file:///F:/writer/validReader/testDtd/HeadCount.xml,?(2,?2).

    Validation?finished


    可以發(fā)現(xiàn)HeadCount.xml文件中第一個(gè)元素不是所期待的HeadCount1,所以報(bào)錯(cuò)。


    恢復(fù)HeadCount.dtd文件,將HeadCount.xml改一下:

    <!DOCTYPE?HeadCount?SYSTEM?"HeadCount.dtd">

    <HeadCount>

    <Name?First1="Waldo"?Last1="Pepper">

    <Name?First="Salt"?Last="Pepper"?Relation="spouse"/>

    <Name?First="Red"?Last="Pepper"?Relation="child"/>

    </Name>

    <Name?First1="&MyFirst;"?Last1="&MyLast;">

    <Name?First="Sharon"?Last="&MyLast;"?Relation="spouse"/>

    <Name?First="Morgan"?Last="&MyLast;"?Relation="child"/>

    <Name?First="Shelby"?Last="&MyLast;"?Relation="child"/>

    </Name>

    </HeadCount>


    既將First改成First1,Last改成Last1,再運(yùn)行這個(gè)程序,結(jié)果如下:

    ***Validation?error

    Severity:Error

    Message?:The?'HeadCount'?element?is?not?declared.?An?error?occurred?at

    file:///F:/writer/validReader/testDtd/HeadCount.xml,?(2,?2).

    Validation?finished


    F:\writer\validReader\testDtd>testDtd

    ***Validation?error

    Severity:Error

    Message?:The?'First1'?attribute?is?not?declared.?An?error?occurred?at?f

    ile:///F:/writer/validReader/testDtd/HeadCount.xml,?(3,?9).

    ***Validation?error

    Severity:Error

    Message?:The?'Last1'?attribute?is?not?declared.?An?error?occurred?at?fi

    le:///F:/writer/validReader/testDtd/HeadCount.xml,?(3,?24).

    ***Validation?error

    Severity:Error

    Message?:The?required?attribute?'Last'?is?missing.?An?error?occurred?at

    file:///F:/writer/validReader/testDtd/HeadCount.xml,?(3,?4).

    ***Validation?error

    Severity:Error

    Message?:The?'First1'?attribute?is?not?declared.?An?error?occurred?at?f

    ile:///F:/writer/validReader/testDtd/HeadCount.xml,?(7,?9).

    ***Validation?error

    Severity:Error

    Message?:The?'Last1'?attribute?is?not?declared.?An?error?occurred?at?fi

    le:///F:/writer/validReader/testDtd/HeadCount.xml,?(7,?28).

    ***Validation?error

    Severity:Error

    Message?:The?required?attribute?'Last'?is?missing.?An?error?occurred?at

    file:///F:/writer/validReader/testDtd/HeadCount.xml,?(7,?4).

    Validation?finished

    通過報(bào)出來的錯(cuò)誤信息,我們可以得知,F(xiàn)irst1和Last1屬性在DTD文件中沒有定義,所以出錯(cuò)。

    通過以上的測(cè)試,可以得知DTD校驗(yàn)的一些簡(jiǎn)單的規(guī)律,它同Xml?Schema校驗(yàn)相輔相成,共同構(gòu)成了XML?校驗(yàn),保證XML數(shù)據(jù)的正確性,是XML成為數(shù)據(jù)承載和傳輸?shù)挠行Ф煽康妮d體。


    XML?問題?#9??SQL?查詢中的?DTD?和?XML?文檔

    本專欄討論了可以不依賴?RDBMS?生成可移植?XML?結(jié)果集的公眾域?sql2dtd?和?sql2xml?實(shí)用程序。從關(guān)系數(shù)據(jù)庫(kù)中抽取數(shù)據(jù)的?SQL?查詢可以提供非常實(shí)用且特殊的文檔類型信息,用于以?XML?表示查詢結(jié)果。
    前一“XML?話題”專欄討論了各種數(shù)據(jù)模型的一些基本理論和它們的優(yōu)勢(shì)。得出的一個(gè)結(jié)論就是?RDBMS?已被普遍接受(有充分的理由),并且在這種環(huán)境中,最好將?XML?看作是在各種?DBMS?之間傳送數(shù)據(jù)的一種方法,而不是替代?DBMS?的事物。雖然?XPath?和?XSLT?可用于某些特定的“數(shù)據(jù)查詢”,但它們的應(yīng)用遠(yuǎn)不及?RDBMS?和(尤其是)SQL?的應(yīng)用廣泛和普遍。不過,由于篇幅限制,我將在以后的專欄中討論?XPath?和?XSLT?的具體性能(和限制)。

    一些近期的?RDBMS(至少包括?DB2、Oracle,可能還有其它一些?RDBMS)都附帶了用于導(dǎo)出?XML?的內(nèi)置(或者至少可選的)工具。不過,在本專欄中討論的工具都具有普遍性;特別是,由這些工具生成的?DTD?對(duì)于對(duì)不同?RDBMS?執(zhí)行的相同查詢都是完全相同的。我希望這對(duì)實(shí)現(xiàn)數(shù)據(jù)透明性的目標(biāo)會(huì)有所幫助。

    過于簡(jiǎn)化
    對(duì)于將關(guān)系數(shù)據(jù)庫(kù)數(shù)據(jù)轉(zhuǎn)換成?XML,您能想像到的最明顯的方式通常也不是什么好的想法。即,它簡(jiǎn)單到?--?無論從概念上還是從實(shí)踐上?--?將?RDBMS?的所有內(nèi)容逐個(gè)表地轉(zhuǎn)儲(chǔ)到相應(yīng)的?XML?文檔中。例如,LIBRARY?數(shù)據(jù)庫(kù)(繼續(xù)上一專欄中那個(gè)簡(jiǎn)單示例)有一個(gè)稱作?BOOKPRICE?的表,其內(nèi)容如下:

    SELECT?*?FROM?BOOKPRICE;
    +------------+-------+
    |?ISBN?|?Price?|
    +------------+-------+
    |?2994927282?|?34.99?|
    |?3920202049?|?47.50?|
    +------------+-------+

    ?

    我可以直接將它轉(zhuǎn)換成如下文檔?BOOKPRICE.xml:

    清單?1.?BOOKPRICE.xml?文檔

    <?xml?version="1.0"?>
    <SQL>
    ?<row>
    ?<ISBN>2994927282</ISBN>
    ?<Price>34.99</Price>
    ?</row>
    ?<row>
    ?<ISBN>3920202049</ISBN>
    ?<Price>47.50</Price>
    ?</row>
    </SQL>


    ?

    為數(shù)據(jù)庫(kù)中的每個(gè)表創(chuàng)建了類似的?XML?文檔后,您就擁有了整個(gè)數(shù)據(jù)庫(kù)的快照。

    適當(dāng)簡(jiǎn)化
    上面勾畫的方法有兩個(gè)基本問題。第一個(gè)問題是?XML?轉(zhuǎn)儲(chǔ)的效率非常低。您已經(jīng)知道,XML?是一種非常冗長(zhǎng)的格式,大型數(shù)據(jù)庫(kù)的?XML?轉(zhuǎn)儲(chǔ)會(huì)生成更大的?XML?文檔集合。而且,一些主要?DBMS?已經(jīng)提供了簡(jiǎn)潔而有效的文本文件或壓縮記錄樣式的轉(zhuǎn)儲(chǔ)。上面所勾畫的?XML?對(duì)這些簡(jiǎn)單格式不但沒有提供任何額外功能,反而顯著地增加了傳送文件的大小。

    第二個(gè)問題比第一個(gè)更有趣。在某種意義上,“DASD?很廉價(jià)”,帶寬也變得越來越廉價(jià)("DASD"?是?IBM?對(duì)“硬盤”的舊稱;這個(gè)措詞在設(shè)計(jì)上很陳腐)。因此單單效率不一定就是最重要的因素。更為重要的是,您幾乎不會(huì)想要將數(shù)據(jù)庫(kù)的全部?jī)?nèi)容與伙伴/部門/用戶等進(jìn)行交流。有時(shí)候,一些內(nèi)容是專用的;而幾乎任何時(shí)候,大多數(shù)內(nèi)容與特定用戶并沒有任何關(guān)系。

    將有用的?SQL?查詢結(jié)果轉(zhuǎn)儲(chǔ)到?XML?中比將原始表轉(zhuǎn)儲(chǔ)到?XML?更有意義。而為了將?XML?事務(wù)或饋送所需的確切語法分析和處理的預(yù)期規(guī)律化,將?DTD?與這些有用的查詢進(jìn)行關(guān)聯(lián)仍然會(huì)比較好。這兩種有趣的操作恰好是公眾域?Python?實(shí)用程序?sql2dtd?和?sql2xml?能夠?qū)崿F(xiàn)的。

    假設(shè)?A?和?B?各自有其自身的內(nèi)部數(shù)據(jù)存儲(chǔ)器策略(例如,在不同的?RDBMS?中)。各自維護(hù)所有種類的相關(guān)信息,這些信息與?A?和?B?之間的交互沒有關(guān)系,但它們又都具有一些希望共享的信息。假設(shè),遵循這樣的路線,A?需要與?B?循環(huán)地就特定種類的數(shù)據(jù)集進(jìn)行通信。A?和?B?可以做的一件事是同意?A?將定期向?B?發(fā)送一組?XML?文檔,每個(gè)文檔都符合事先一致認(rèn)可的?DTD。一個(gè)傳輸中的特定數(shù)據(jù)將隨時(shí)間而有所不同,但有效性規(guī)則已事先指定。只要?A?和?B?知道它們之間的協(xié)議,就可以執(zhí)行它們的編程。

    生成?DTD
    開發(fā)?A?和?B?之間的這種通信的一個(gè)方法是開發(fā)與?A?和?B?特定需要相匹配的?DTD(或模式)。然后,A?需要開發(fā)定制代碼來將數(shù)據(jù)從?A?的當(dāng)前?RDBMS?導(dǎo)出到符合一致的?DTD?中;B?需要開發(fā)定制代碼來導(dǎo)入相同的數(shù)據(jù)(到結(jié)構(gòu)不同的數(shù)據(jù)庫(kù)中)。最后,通信通道被打開。

    不過通常存在一種更快速的方法?--?往往利用現(xiàn)有導(dǎo)出/導(dǎo)入過程的一種方法。“標(biāo)準(zhǔn)查詢語言?(SQL)”是一種能夠確切表達(dá)?RDBMS?數(shù)據(jù)庫(kù)中您所感興趣的數(shù)據(jù)的極其簡(jiǎn)潔的方法。嘗試將例如?XPath?或?XSLT?這樣的?XML?原始技術(shù)合并到關(guān)系模型上可能不太自然,盡管它們必定可以在?XML?的基本分層模型中表達(dá)查詢功能。

    許多組織已經(jīng)開發(fā)出為實(shí)現(xiàn)已知任務(wù)的、經(jīng)過了徹底測(cè)試的幾組?SQL?語句。事實(shí)上,RDBMS?往往提供了用于優(yōu)化已存儲(chǔ)查詢的方法。雖然肯定有一些為數(shù)據(jù)交換而設(shè)計(jì)的豐富的?DTD?比較有意義的情況,但在許多或者大多數(shù)情況下,在?SQL?查詢中隱式地使用結(jié)構(gòu)信息作為?SQL?數(shù)據(jù)傳輸?shù)模ㄗ詣?dòng))基礎(chǔ)是種很好的解決方案。

    雖然?SQL?查詢可以以復(fù)雜的方法來組合表數(shù)據(jù),但所有?SQL?查詢的結(jié)果都是相當(dāng)簡(jiǎn)單的“行與列”的排列。在查詢輸出中,列的數(shù)量是固定的,每行填入了每個(gè)固定列的值。(即,除了數(shù)量上沒有改變以外,無論是值的類型還是列名在?SQL?結(jié)果中均無改變?--?即使它們可能在?XML?文檔中有所改變)。XML?表示元素復(fù)雜嵌套模式的潛力在表示?SQL?結(jié)果中并沒有得到深層的體現(xiàn)。雖然如此,SQL?查詢的一些重要方面可以而且也應(yīng)該在簡(jiǎn)單的行/列位置以外以?XML?DTD?表示。

    要表示?SQL?查詢中的哪些內(nèi)容?
    我認(rèn)為在?A?和?B?之間預(yù)期的數(shù)據(jù)交換中,應(yīng)該區(qū)分出兩方面。一方面,是?A?數(shù)據(jù)的內(nèi)部組織?--?例如,其標(biāo)準(zhǔn)化和取消標(biāo)準(zhǔn)化優(yōu)化。B?沒有,也不需要考慮?A?的內(nèi)在方面。另一方面,存在描述實(shí)際發(fā)送內(nèi)容的元數(shù)據(jù)。當(dāng)然,區(qū)分這些方面不一定很容易。

    在編寫?sql2dtd(和幫助規(guī)劃?Scott?Hathaway?的?sql2xml)時(shí),我做了一些決定,確定了哪些屬于數(shù)據(jù)傳輸?shù)牟糠郑男┪挥诎l(fā)送方設(shè)置的內(nèi)部(不需要以?DTD?表示)。清單?2?所顯示的樣本?XML(帶有作為內(nèi)部集的?DTD)輸出有助于說明這些決定(該輸出完全從作為屬性包含的?SQL?查詢生成;當(dāng)然,是在對(duì)合適的數(shù)據(jù)庫(kù)運(yùn)行時(shí)):

    清單?2.?帶有作為內(nèi)部集的?DTD?的樣本?XML?輸出

    <?xml?version="1.0"?>
    <!DOCTYPE?SQL?[
    <!ELEMENT?SQL?(row)*>
    <!ATTLIST?SQL
    ?GROUP_BY?NMTOKEN?#FIXED?"AuthID"
    ?query?CDATA?#FIXED?"SELECT?AuthID?AS?SSN,COUNT(GroupID)
    ?FROM?AUTHGROUP?GROUP?BY?AuthID
    ?ORDER?BY?AuthID"
    >
    <!ELEMENT?row?(SSN,?column2)>
    <!ATTLIST?row?num?ID?#IMPLIED>
    <!ELEMENT?SSN?(#PCDATA)>
    <!ELEMENT?column2?(#PCDATA)>
    <!ATTLIST?column2?CALC?CDATA?#FIXED?"COUNT(GroupID)">
    ]>

    <SQL>
    ?<row?num="1">
    ?<SSN>111-22-3333</SSN>
    ?<column2>1</column2>
    ?</row>
    ?<row?num="2">
    ?<SSN>333-22-4444</SSN>
    ?<column2>2</column2>
    ?</row>
    ?<row?num="3">
    ?<SSN>666-44-5555</SSN>
    ?<column2>1</column2>
    ?</row>
    </SQL>


    ?

    這個(gè)簡(jiǎn)單的?XML?文檔實(shí)際上可以包含比人們最初時(shí)所注意到的更多的元數(shù)據(jù)。當(dāng)然,通過將?SQL?本身作為根節(jié)點(diǎn)的一個(gè)屬性包含在內(nèi),人們可以重新構(gòu)造?SQL?中固有的任何事物。但這樣做需要對(duì)?SQL?重新進(jìn)行語法分析,sql2dtd?已在文檔中表示過它,因此通常這沒有必要。

    CALC?屬性的規(guī)范包含這樣一個(gè)事實(shí),即?XML?包含了計(jì)算過的元素。因?yàn)橛?jì)算過的表達(dá)式可能很長(zhǎng),并且可能包含對(duì)于?XML?標(biāo)記來說非法的字符,所以計(jì)算過的列僅由它們的位置命名。不過,加入元素內(nèi)容的特定計(jì)算是作為標(biāo)記的一個(gè)屬性包含在內(nèi)的。為了避免在?XML?主體中重復(fù)屬性,它在?DTD?中指定為?#FIXED。

    如果使用計(jì)算過的列,計(jì)算往往反映使用?"GROUP?BY"?修飾符對(duì)列所進(jìn)行的分組。所有這樣的分組都在根元素的?GROUP_BY?屬性中列出。

    而且,如果使用了?"ORDER?BY"?子句,每個(gè)?<row>?標(biāo)記就會(huì)帶有指定輸出數(shù)據(jù)序列的?num?屬性。不過,如果結(jié)果集是無序的,則不使用?num?屬性。

    讓我們考慮一下在?DTD?中有什么東西沒有表示,就會(huì)發(fā)現(xiàn)它實(shí)際上確實(shí)屬于?A?的內(nèi)部數(shù)據(jù)表示,而不屬于發(fā)送的消息。

    除了嵌入的原始?SQL?查詢以外,沒有保留用于查詢數(shù)據(jù)的一個(gè)或多個(gè)表的表示("FROM"?子句)。特殊的表組織只不過不是?B?需要感興趣的一些事物。事實(shí)上,A?可以在有適當(dāng)傳輸協(xié)議之后徹底地修改其數(shù)據(jù)庫(kù)設(shè)計(jì);但只要通過一些手段抽取相同的字段(列),B?就不需要擔(dān)心這一點(diǎn)。尤其是,因?yàn)?"AS"?子句覆蓋了實(shí)際的表的列名,所以有可能繼續(xù)發(fā)送在?A?數(shù)據(jù)庫(kù)中不再擁有任何直接文字意義的?XML?元素。

    在?sql2dtd?設(shè)計(jì)中最重要的一點(diǎn)是忽略了?"WHERE"?和?"HAVING"?子句(以及?JOIN、DISTINCT?和?ALL?修飾符)。和表名一樣,將數(shù)據(jù)從?A?的那些表中取出所必需的特定聯(lián)接和過濾器不是?B?應(yīng)該擔(dān)心的問題。如果?A?碰巧需要將一些表聯(lián)接在一起以獲得一些數(shù)據(jù),那只是?A?的一個(gè)標(biāo)準(zhǔn)化策略。B?可以使用也可以不使用任何類似的策略(對(duì)于不同的數(shù)據(jù)子集),兩種方法都不用擔(dān)心?A?的操作。出于相關(guān)但稍微不同的理由忽略過濾器(主要使用?"WHERE"?子句或?"DISTINCT"?修飾符)。不管出于何種商業(yè)原因,如果?A?只需要告之?B?那些其?whatzit?大于?25?的?woozles,從?B?的角度來說,它只是屬于?woozles?的性質(zhì)。即,A?可能對(duì)?B?不關(guān)心的?woozles?的一個(gè)子類感興趣;但是?A?需要通過使用過濾器來獲得感興趣的內(nèi)容(與不擁有它們,或?qū)⑺鼈兎旁诹硪粋€(gè)表中相反)這一特定事實(shí)并不是?B?需要擔(dān)心的。從這一方面來說,sub-select?只是另一種過濾器。

    結(jié)束
    我還沒有介紹?sql2dtd?和?sql2xml?的任何特定用法。這里不需要做太多解釋,因?yàn)樗鼈冏约阂言趦?nèi)部詳細(xì)說明了。一般情況下,?sql2dtd?可以從?SQL?查詢生成?DTD,但它本身并不查詢?nèi)魏螖?shù)據(jù)庫(kù)。sql2xml?通過?ODBC?執(zhí)行查詢,并可以利用?sql2dtd?來獲得?DTD(它也可以生成?DTD?較少的?XML文檔)。

    這些工具只對(duì)?A?和?B?之間預(yù)期大約一半過程有所幫助。A?和?B?可以快速地使用這些工具達(dá)到?DTD,A?可以同樣快速地生成符合這些?DTD?的輸出?XML?文檔。但?B?最終仍需要執(zhí)行語法分析、存儲(chǔ)和處理這些接收到的文檔所涉及的所有工作。以后的專欄將更詳細(xì)地討論?B?的任務(wù)。


    簡(jiǎn)單的DTD例子描述和分析


     下面舉一個(gè)帶有內(nèi)部DTD的XML文檔的例子:?

      <?xml?version="1.0"?encoding="GB2312"??>?
      <!DOCTYPE?家庭?[?
       <!ELEMENT?家庭?(人+,家電*)>?
       <!ELEMENT人?EMPTY>?
       <!ELEMENT?家電?EMPTY>?
       <!ATTLIST?人?
        名字?CDATA?#REQUIRED?
        性別?(男|女)?#REQUIRED?
        年齡?CDATA?#REQUIRED?
        愛好?CDATA?#IMPLIED?
       >?
       <!ATTLIST?家電?
         名稱?CDATA?#REQUIRED?
         數(shù)量?CDATA?#REQUIRED?
         說明?CDATA?#IMPLIED?
        >?
      ]>??
      <家庭>?
      <人>?
      <名字>郭大路?
      <性別>男?
      <年齡>25?
      ?
      <人>?
      <名字>李尋歡?
      <性別>男?
      <年齡>38?
      <愛好>作個(gè)教育家和偉人?
      ?
      <家電>?
      <名稱>彩電?
      <數(shù)量>3?
      ?
      ?

      這個(gè)文檔從第二行開始進(jìn)行文檔類型聲明,包含了文檔元素(家庭)的名稱。根據(jù)定義,我們發(fā)現(xiàn)該元素可以包含一個(gè)或者多個(gè)人(由這個(gè)+號(hào)決定的),可以包含零個(gè)或多個(gè)家電(由這個(gè)*符號(hào)決定),然后定義了人這個(gè)元素的需要的屬性,其中名字、性別和年齡是必須的,而愛好可以填有也可以不填。家電的名字和數(shù)量屬性必須有,但說明可以寫也可以不寫。?

      如果采用外部DTD的話,就需要有兩個(gè)文檔,第一個(gè)文檔就是關(guān)于DTD的文檔,第二個(gè)文檔就是遵守DTD格式的內(nèi)容文檔。實(shí)際上我們可以建立無窮多個(gè)遵守該DTD格式的文檔。舉一個(gè)例子來說,我們?cè)跇?gòu)造關(guān)系數(shù)據(jù)庫(kù)中的表的時(shí)候,我們需要定義好表的結(jié)構(gòu)(也就是表包含的字段集合),然后我們就可以往這個(gè)表中放入記錄,記錄的個(gè)數(shù)從理論上講可以是無窮多個(gè)的。這里關(guān)于表的結(jié)構(gòu)就類似于DTD文檔。記錄類似于遵守DTD格式的內(nèi)容文檔。外部DTD的好處是:它可以方便高效地被多個(gè)XML文件所共享。你只要寫一個(gè)DTD文件,就可以被多個(gè)XML文件所引用。事實(shí)上,當(dāng)許多組織需要統(tǒng)一它們的數(shù)據(jù)交換格式時(shí),它們就是通過外部DTD來完成的。這樣做不僅簡(jiǎn)化了輸入工作,還保證當(dāng)你需要對(duì)DTD做出改動(dòng)時(shí),不用一一去改每個(gè)引用了它的XML文件,只要改一個(gè)公用的DTD文件就足夠了。不過需要注意,如果DTD的改動(dòng)不是"向后兼容"的,這時(shí)原先根據(jù)該DTD編寫的那些XML文件可能就會(huì)出問題了。?

      現(xiàn)在我們就嘗試建立一個(gè)DTD文檔,不妨命名為Home.dtd。其代碼如下:?

      <?xml?version="1.0"?encoding="GB2312"??>?
      <!ELEMENT?家庭?(人+,家電*)>?
      <!ELEMENT人?EMPTY>?
      <!ELEMENT?家電?EMPTY>?
      <!ATTLIST?人?
        名字?CDATA?#REQUIRED?
        性別?(男|女)?#REQUIRED?
        年齡?CDATA?#REQUIRED?
        愛好?CDATA?#IMPLIED?
       >?
      <!ATTLIST?家電?
       名稱?CDATA?#REQUIRED?
       數(shù)量?CDATA?#REQUIRED?
       說明?CDATA?#IMPLIED?
      >?

      然后,我們可以建立一個(gè)遵守該DTD格式的內(nèi)容文檔,不妨設(shè)為HomeInstance.xml。其代碼如下:?

      <?xml?version="1.0"?encoding="GB2312"??>?
      <!DOCTYPE?家庭?SYSTEM?"Home.dtd">?
      <家庭>?
      <人>?
      <名字>郭大路?
      <性別>男?
      <年齡>25?
      ?
      <人>?
      <名字>李尋歡?
      <性別>男?
      <年齡>38?
      <愛好>作個(gè)教育家和偉人?
      ?
      <家電>?
      <名稱>彩電?
      <數(shù)量>3?
      ?
      ?

      把這兩個(gè)文檔放到同一個(gè)目錄下,然后可以用XML瀏覽器對(duì)HomeInstance.xml進(jìn)行瀏覽,結(jié)果應(yīng)該和使用內(nèi)部DTD的結(jié)果一樣。?

      眾所周知,在設(shè)計(jì)MIS應(yīng)用程序的時(shí)候,重要的是要進(jìn)行E-R圖設(shè)計(jì),然后建立關(guān)系數(shù)據(jù)庫(kù),建立數(shù)據(jù)庫(kù)的關(guān)鍵就是要定義好表的格式,并使它的范式盡可能的高。對(duì)應(yīng)的,建立基于XML應(yīng)用的關(guān)鍵就是要定義好DTD,然后所有的內(nèi)容就按照DTD格式進(jìn)行編寫。DTD實(shí)際上表現(xiàn)了一個(gè)層次的關(guān)系,你也可以把它理解成一棵樹的結(jié)構(gòu)。樹中的節(jié)點(diǎn)實(shí)際上就是一個(gè)個(gè)元素(ELEMENT),一個(gè)元素可以包含其他的元素。比如上面的例子中家庭這個(gè)元素包含了人和家電這兩個(gè)元素。一個(gè)元素可以包含屬性(ATTLIST)也可以沒有任何屬性。比如上面的例子中,家庭這個(gè)元素就沒有任何屬性,而人和家電都有自己的屬性。?

      際上如果大家學(xué)過編譯系統(tǒng)的話,都知道對(duì)編程語言進(jìn)行語法定義的工具:巴科斯-諾爾范式。它是用來對(duì)語言的語法進(jìn)行定義的工具。實(shí)際上DTD就是起到了類似的作用。

    posted on 2006-05-24 00:45 船長(zhǎng) 閱讀(3962) 評(píng)論(0)  編輯  收藏 所屬分類: J2EE
    主站蜘蛛池模板: 一级a性色生活片久久无少妇一级婬片免费放 | 亚洲免费观看视频| 精品熟女少妇av免费久久| 亚洲av无码一区二区三区天堂古代 | 免费一看一级毛片全播放| a色毛片免费视频| 精品亚洲成A人无码成A在线观看| 亚洲高清视频一视频二视频三| 先锋影音资源片午夜在线观看视频免费播放 | 99在线精品免费视频九九视| 美女啪啪网站又黄又免费| 亚洲午夜在线电影| 高清在线亚洲精品国产二区| 120秒男女动态视频免费| 色婷婷综合缴情综免费观看| 亚洲国产亚洲片在线观看播放| 亚洲女人被黑人巨大进入| xxxx日本免费| 中文字幕的电影免费网站| 亚洲色成人四虎在线观看| 亚洲大尺度无码专区尤物| 免费看小12萝裸体视频国产| 成年黄网站色大免费全看| 中文字幕一区二区免费| 黄色网址在线免费观看| 久久精品国产亚洲av麻豆蜜芽| 国产亚洲精品美女久久久| 国产jizzjizz视频全部免费| 2021久久精品免费观看| 日本在线看片免费| 精品一区二区三区免费观看| 亚洲AV香蕉一区区二区三区| 亚洲三级视频在线| 久久夜色精品国产噜噜亚洲AV| 综合亚洲伊人午夜网| 免费大香伊蕉在人线国产 | 久久精品亚洲男人的天堂| 操美女视频免费网站| 18成禁人视频免费网站| 免费A级毛片无码视频| 中文字幕手机在线免费看电影 |