2010-04-12 50 views
3

我正在編寫xsd和要驗證的代碼,所以我在這裏有很好的控制權。要根據多個xsd模式進行驗證的XML

我想有一個上傳工具,可以根據xml文件向我的應用程序添加東西。 xml文件的一部分應根據其他部分中的其中一個值針對不同模式進行驗證。下面是一個例子來說明:

<foo> 
    <name>Harold</name> 
    <bar>Alpha</bar> 
    <baz>Mercury</baz> 
    <!-- ... more general info that applies to all foos ... --> 

    <bar-config> 
    <!-- the content here is specific to the bar named "Alpha" --> 
    </bar-config> 
    <baz-config> 
    <!-- the content here is specific to the baz named "Mercury" --> 
    </baz> 
</foo> 

在這種情況下,存在的<bar>內容控制的一些詞彙,我能處理的部分就好了。然後,根據bar值,應該使用適當的xml模式來驗證bar-config的內容。同樣適用於baz和baz-config。

執行解析/驗證的代碼是用Java編寫的。不確定解決方案將如何依賴於語言。

理想情況下,該解決方案將允許xml作者聲明合適的模式位置以及什麼不是,以便他/她可以在充分智能的編輯器中實時驗證xml。

此外,<bar><baz>的可能值是正交的,所以我不想通過擴展來爲每個可能的酒吧/巴茲組合進行此操作。我的意思是,如果有24個可能的bar值/模式和8個可能的baz值/模式,我希望能夠編寫1 + 24 + 8 = 33個總模式,而不是1 * 24 * 8 = 192個總模式。

此外,如果可能的話,我寧願不把bar-config和baz-config分成單獨的xml文件。我意識到可能會讓所有問題變得更容易,因爲每個xml文件都只有一個模式,但我試圖查看是否有一個很好的單一xml文件解決方案。

回答

5

我終於明白了這一點。

首先,在foo的架構,則條形配置和baz-配置元素具有一種類型,它包括一個any元件,這樣:

<sequence> 
    <any minOccurs="0" maxOccurs="1" 
     processContents="lax" namespace="##any" /> 
</sequence> 

在XML中,然後,必須指定使用xmlns屬性欄,配置或巴茲 - 配置的子元素在正確的命名空間,就像這樣:

<bar-config> 
    <config xmlns="http://www.example.org/bar/Alpha"> 
     ... config xml here ... 
    </config> 
</bar-config> 

然後,酒吧阿爾法你的XML schema文件將有http://www.example.org/bar/Alpha目標命名空間,將定義根元素ent config

如果您的XML文件具有兩個模式文件的名稱空間聲明和模式位置,這足以讓編輯器執行所有驗證(至少對Eclipse來說足夠好)。

到目前爲止,我們已經滿足了xml作者可以以在編輯器中驗證的方式編寫xml的要求。

現在,我們需要消費者能夠驗證。就我而言,我正在使用Java。

如果由於某些原因,你知道你將需要使用驗證的時間提前架構文件,那麼你只需創建一個單一的架構對象和驗證像往常一樣,像這樣:

Schema schema = factory().newSchema(new Source[] { 
    new StreamSource(stream("foo.xsd")), 
    new StreamSource(stream("Alpha.xsd")), 
    new StreamSource(stream("Mercury.xsd")), 
}); 

在在這種情況下,我們不知道在解析主文檔之前要使用哪些xsd文件。所以,一般的程序是:

  1. 驗證僅使用主(富)XML模式
  2. 確定模式使用來驗證文檔
  3. 的部分查找是根的節點該部分的驗證使用一個單獨的模式
  4. 導入該節點至全新的文件
  5. 驗證使用其他模式文件
全新的文件

警告:看起來文檔必須構建名稱空間感知才能使其工作。

下面是一些代碼(這是從我的代碼不同的地方裂開,所以可能會有一些錯誤,通過複製和粘貼引入):

// Contains the filename of the xml file 
String filename; 

// Load the xml data using a namespace-aware builder (the method 
// 'stream' simply opens an input stream on a file) 
Document document; 
DocumentBuilderFactory docBuilderFactory = 
    DocumentBuilderFactory.newInstance(); 
docBuilderFactory.setNamespaceAware(true); 
document = docBuilderFactory.newDocumentBuilder().parse(stream(filename)); 

// Create the schema factory 
SchemaFactory sFactory = SchemaFactory.newInstance(
    XMLConstants.W3C_XML_SCHEMA_NS_URI); 

// Load the main schema 
Schema schema = sFactory.newSchema(
    new StreamSource(stream("foo.xsd"))); 

// Validate using main schema 
schema.newValidator().validate(new DOMSource(document)); 

// Get the node that is the root for the portion you want to validate 
// using another schema 
Node node= getSpecialNode(document); 

// Build a Document from that node 
Document subDocument = docBuilderFactory.newDocumentBuilder().newDocument(); 
subDocument.appendChild(subDocument.importNode(node, true)); 

// Determine the schema to use using your own logic 
Schema subSchema = parseAndDetermineSchema(document); 

// Validate using other schema 
subSchema.newValidator().validate(new DOMSource(subDocument)); 
0

您需要爲實例文檔的每個單獨驗證部分定義一個目標命名空間。然後你定義一個master schema,它使用<xsd:include>來引用這些組件的模式文檔。

該方法的侷限性在於,您不能讓各個組件定義應該用於驗證它們的模式。但是,通常讓文檔告訴你如何驗證它(例如驗證應該由應用程序控制)。