2012-04-12 44 views
16

Dưới đây là một XSD:Sử dụng XSD với bao gồm

<?xml version="1.0"?> 
<xsd:schema 
elementFormDefault='unqualified' 
attributeFormDefault='unqualified' 
xmlns:xsd='http://www.w3.org/2001/XMLSchema' 
> 

    <xsd:simpleType name='TheSimpleType'> 
    <xsd:restriction base='xsd:string' /> 
    </xsd:simpleType> 
</xsd:schema> 

Đây là một XSD thứ hai bao gồm một ở trên:

<?xml version="1.0" encoding="UTF-8" ?> 
<xsd:schema 
elementFormDefault='unqualified' 
attributeFormDefault='unqualified' 
xmlns:xsd='http://www.w3.org/2001/XMLSchema' 
targetNamespace='a' 
xmlns='a' 
> 

    <xsd:include schemaLocation='Include.xsd' /> 

    <xsd:element name = "TheElement" > 
    <xsd:complexType> 
    <xsd:attribute name="Code" type="TheSimpleType" use="required"/> 
    </xsd:complexType> 
    </xsd:element> 
</xsd:schema> 

tôi cần phải đọc (thứ hai) XSD vào C# và:

  1. kiểm tra xem đó có phải là XSD hợp lệ và
  2. xác thực tài liệu chống lại nó.

Dưới đây là một số C# để đọc trong lược đồ:

XmlSchemaSet schemaSet = new XmlSchemaSet(); 
    foreach (string sd in Schemas) 
    { 
     using (XmlReader r = XmlReader.Create(new FileStream(sd, FileMode.Open))) 
     { 
      schemaSet.Add(XmlSchema.Read(r, null)); 
     } 
    } 
    schemaSet.CompilationSettings = new XmlSchemaCompilationSettings(); 
    schemaSet.Compile(); 

Các .Compile() không thành công vì "Type. 'A: TheSimpleType' không được công bố, hoặc không phải là một kiểu đơn giản"

Tuy nhiên, nó hoạt động nếu một trong hai:

  • không gian tên được lấy ra từ các lược đồ, hoặc
  • không gian tên được thêm vào bao gồm.

Câu hỏi đặt ra là: làm thế nào để C# chấp nhận nó mà không cần chỉnh sửa sơ đồ?

Tôi nghi ngờ vấn đề là mặc dù tôi đã đặt cả hai sơ đồ vào XmlSchemaSet, tôi vẫn cần phải nói với C# rằng một được bao gồm trong khác, tức là, nó đã không làm việc nó ra cho chính nó. Thật vậy, nếu tôi chỉ nói cho XmlSchemaSet về XSD chính (và không bao gồm) (cả hai không có các không gian tên()) thì "Type 'TheSimpleType' không được khai báo, hoặc không phải là một kiểu đơn giản."

Vì vậy, điều này dường như là một câu hỏi về giải quyết bao gồm: làm thế nào ?!

Trả lời

4

Bạn có thể sử dụng XmlSchema.Includes để liên kết chúng với nhau. Sau đó, bạn chỉ cần thêm các giản đồ chính để tập schema:

var includeSchema = XmlSchema.Read(XmlReader.Create(...), null); 
var mainSchema = XmlSchema.Read(XmlReader.Create(...), null); 

var include = new XmlSchemaInclude(); 
include.Schema = includeSchema; 
mainSchema.Includes.Add(include); 

var schemaSet = new XmlSchemaSet(); 
schemaSet.Add(mainSchema); 
schemaSet.Compile(); 
+1

+1 chưa bao giờ biết về lớp 'XmlSchemaInclude'. Câu trả lời chính xác. – psubsee2003

+2

OK, tốt. Nhưng bây giờ giả sử rằng tôi phải xác định tất cả các tính năng bao gồm trong thời gian chạy, tức là, tôi cung cấp cho bạn một XSD tùy ý kèm theo và bạn phải truy cập và tìm nạp tất cả chúng. –

+0

's = XmlSchema.Read (r, null);' Bây giờ tôi thấy chúng ta có 's.Includes' là các đối tượng' XmlSchemaInclude', và nó được điền chính xác (với 1 bao gồm). –

0

Hãy thử điều này: D

public static XmlSchema LoadSchema(string pathname) 
{ 
    XmlSchema s = null; 
    XmlValidationHandler h = new XmlValidationHandler(); 
    using (XmlReader r = XmlReader.Create(new FileStream(pathname, FileMode.Open))) 
    { 
     s = XmlSchema.Read(r, new ValidationEventHandler(h.HandleValidationEvent)); 
    } 

    if (h.Errors.Count > 0) 
    { 
     throw new Exception(string.Format("There were {1} errors reading the XSD at {0}. The first is: {2}.", pathname, h.Errors.Count, h.Errors[0])); 
    } 

    return s; 
} 

public static XmlSchema LoadSchemaAndResolveIncludes(string pathname) 
{ 
    FileInfo f = new FileInfo(pathname); 
    XmlSchema s = LoadSchema(f.FullName); 

    foreach(XmlSchemaInclude i in s.Includes) 
    { 
     XmlSchema si = LoadSchema(f.Directory.FullName + @"\" + i.SchemaLocation); 
     si.TargetNamespace = s.TargetNamespace; 
     i.Schema = si; 
    } 

    return s; 
} 

public static List<ValidationEventArgs> Validate(string pathnameDocument, string pathnameSchema) 
{ 
    XmlSchema s = LoadSchemaAndResolveIncludes(pathnameSchema); 

    XmlValidationHandler h = new XmlValidationHandler(); 

    XmlDocument x = new XmlDocument(); 
    x.Load(pathnameDocument); 
    x.Schemas.Add(s); 
    s.Compile(new ValidationEventHandler(h.HandleValidationEvent)); 
    x.Validate(new ValidationEventHandler(h.HandleValidationEvent)); 
    return h.Errors; 
} 

Lưu ý đặc biệt là si.TargetNamespace = s.TargetNamespace;.

Rõ ràng, điều này giả định rằng bao gồm được chỉ định dưới dạng đường dẫn tệp liên quan đến giản đồ mà chúng được đưa vào.

+0

Điều này không thành công trong trường hợp khi (A bao gồm B và C) và (tham chiếu B nhưng không bao gồm C). Nó thực sự là cần thiết để viết một XmlResolver tùy chỉnh để giải quyết các tên tập tin. –

25

Vấn đề là với cách giản đồ được mở cho việc đọc trên dòng:

XmlReader.Create(new FileStream(sd, FileMode.Open) 

tôi đã phải viết của riêng tôi XmlResolver trước khi tôi có thể nhìn thấy cách các đường dẫn đến các tập tin bao gồm đã được giải quyết: nó là từ thư mục của tệp thực thi và không phải từ thư mục của lược đồ gốc. Vấn đề là lược đồ cha mẹ không nhận được tập hợp BaseURI của nó. Dưới đây là cách lược đồ phải được mở:

XmlReader.Create(new FileStream(pathname, FileMode.Open, FileAccess.Read),null, pathname) 
+0

Tương tự như vậy, cảm ơn cho rằng Richard + 1. Đã dành cách để kéo dài tóc của tôi ra trên này! – CountZero

+0

Điều này làm việc cho tôi khi tôi sử dụng 'System.IO.Path (tên đường dẫn)' cho đối số 'baseUri' của Tạo. –

0

Đây là phương pháp tôi đã viết để xử lý xác thực xsd. Hy vọng điều này sẽ giúp một số.

 /// <summary> 
     /// Ensure all xsd imported xsd documented are in same folder as master xsd 
     /// </summary> 
     public XsdXmlValidatorResult Validate(string xmlPath, string xsdPath, string xsdNameSpace) 
     { 
      var result = new XsdXmlValidatorResult(); 
      var readerSettings = new XmlReaderSettings {ValidationType = ValidationType.Schema}; 
      readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema; 
      readerSettings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation; 
      readerSettings.Schemas.Add(null, xsdPath); 

      readerSettings.ValidationEventHandler += (sender, args) => 
       { 
        switch (args.Severity) 
        { 
         case XmlSeverityType.Warning: 
          result.Warnings.Add(args.Message); 
          break; 
         case XmlSeverityType.Error: 
          result.IsValid = false; 
          result.Warnings.Add(args.Message); 
          break; 
        } 
       }; 

      var reader = XmlReader.Create(xmlPath, readerSettings); 

      while (reader.Read()) { } 

      return result; 
     } 
+0

Điều này không hoạt động trong trường hợp của tôi. Tất cả các tệp XSD (và XML) đều nằm trong cùng một thư mục. Tuy nhiên, nó nói với tôi rằng các loại được định nghĩa trong xsd đi kèm không được định nghĩa – CeOnSql

Các vấn đề liên quan