c#
  • xml
  • xsd
  • xml-namespaces
  • 2012-04-12 19 views 16 likes 
    16

    Oto XSD:Korzystanie XSD z obejmuje

    <?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> 
    

    Oto drugi XSD, która obejmuje jeden powyżej:

    <?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> 
    

    I trzeba czytać (drugi) XSD do C# i:

    1. sprawdzić, że jest to ważny XSD i
    2. dokumenty walidacji przeciwko niemu.

    Oto niektóre C#, aby przeczytać w schematach:

    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(); 
    

    .Compile() nie działa, ponieważ "Type 'A: TheSimpleType' nie jest zadeklarowana, czy nie jest to prosty typ"

    Jednak to działa jeśli:

    • przestrzeń nazw jest usuwany ze schematu, lub
    • przestrzeń nazw jest dodawany do include.

    Pytanie brzmi: w jaki sposób mogę uzyskać C#, aby zaakceptować to bez edytowania schematów?

    Podejrzewam, że problem polega na tym, że chociaż umieściłem oba schematy w XmlSchemaSet, nadal muszę powiedzieć C#, że jeden jest zawarty w drugim, tj. Nie wyszedł sam z siebie. Rzeczywiście, jeśli tylko opowiem XmlSchemaSet o głównym XSD (a nie o dołączeniu) (oba bez (lub z) przestrzeniami nazw), wówczas "Typ" TheSimpleType "nie jest zadeklarowany lub nie jest prostym typem."

    W związku z tym wydaje się, że to pytanie dotyczy rozwiązania: w jaki sposób ?!

    Odpowiedz

    4

    Możesz użyć XmlSchema.Includes, aby połączyć je ze sobą. Następnie wystarczy dodać główny schemat do zestawu schematu:

    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 nigdy nie wiedział o klasie 'XmlSchemaInclude'. Świetna odpowiedź. – psubsee2003

    +2

    OK, dobrze. Ale teraz przypuśćmy, że muszę określić wszystkie załączenia w czasie wykonywania, tj. Dam ci arbitralny XSD z zawartością i musisz iść i pobrać je wszystkie. –

    +0

    's = XmlSchema.Read (r, null);' Teraz widzę, że mamy 's.Includes', które są obiektami' XmlSchemaInclude' i jest poprawnie wypełniony (z 1). –

    0

    Spróbuj tego: 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; 
    } 
    

    notatkę w szczególności si.TargetNamespace = s.TargetNamespace;.

    Oczywiście zakłada się, że załączniki są określone jako ścieżki do plików w stosunku do schematu, do którego są dołączone.

    +0

    Nie powiedzie się to w przypadku, gdy (A obejmuje B i C) i (odniesienia B, ale nie obejmuje C). Naprawdę konieczne jest napisanie niestandardowego XmlResolver, aby rozwiązać nazwy plików. –

    25

    Problemem jest to ze sposobu schematu jest otwarty do czytania na linii:

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

    musiałem napisać własny XmlResolver zanim mogłem zobaczyć, jak ścieżki do plików zawierających były rozwiązane: go był z katalogu wykonywalnego, a nie z katalogu schematu nadrzędnego. Problem polega na tym, że schematu nadrzędnego nie ustawiono w ustawieniu BaseURI. Oto, jak schemat musi zostać otwarty:

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

    Podobnie, dzięki za to Richard + 1. Zużyłem sposób na długie wyciąganie włosów z tego! – CountZero

    +0

    To działało dla mnie, gdy użyłem 'System.IO.Path (pathname)' dla argumentu 'baseUri' Create. –

    0

    Oto metoda, którą napisałem, aby obsłużyć walidację xsd. Mam nadzieję, że to pomaga niektórym.

     /// <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

    To nie działa w moim przypadku. Wszystkie pliki XSD (i XML) znajdują się w tym samym folderze. Niemniej jednak mówi mi, że typy zdefiniowane w dołączonym xsd nie są zdefiniowane – CeOnSql

    Powiązane problemy