Memvalidasi XML terhadap XSD yang dirujuk dalam C #

161

Saya memiliki file XML dengan lokasi skema tertentu seperti ini:

xsi:schemaLocation="someurl ..\localSchemaPath.xsd"

Saya ingin memvalidasi dalam C #. Visual Studio, ketika saya membuka file, memvalidasi terhadap skema dan daftar kesalahan dengan sempurna. Namun, entah bagaimana, saya tidak dapat memvalidasi secara otomatis dalam C # tanpa menentukan skema yang akan divalidasi seperti:

XmlDocument asset = new XmlDocument();

XmlTextReader schemaReader = new XmlTextReader("relativeSchemaPath");
XmlSchema schema = XmlSchema.Read(schemaReader, SchemaValidationHandler);

asset.Schemas.Add(schema);

asset.Load(filename);
asset.Validate(DocumentValidationHandler);

Tidakkah saya harus dapat memvalidasi dengan skema yang ditentukan dalam file XML secara otomatis? Apa yang saya lewatkan?

jfclavette
sumber

Jawaban:

167

Anda perlu membuat turunan XmlReaderSettings dan meneruskannya ke XmlReader saat Anda membuatnya. Kemudian Anda dapat berlangganan ke ValidationEventHandlerdalam pengaturan untuk menerima kesalahan validasi. Kode Anda akan terlihat seperti ini:

using System.Xml;
using System.Xml.Schema;
using System.IO;

public class ValidXSD
{
    public static void Main()
    {

        // Set the validation settings.
        XmlReaderSettings settings = new XmlReaderSettings();
        settings.ValidationType = ValidationType.Schema;
        settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
        settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
        settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
        settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);

        // Create the XmlReader object.
        XmlReader reader = XmlReader.Create("inlineSchema.xml", settings);

        // Parse the file. 
        while (reader.Read()) ;

    }
    // Display any warnings or errors.
    private static void ValidationCallBack(object sender, ValidationEventArgs args)
    {
        if (args.Severity == XmlSeverityType.Warning)
            Console.WriteLine("\tWarning: Matching schema not found.  No validation occurred." + args.Message);
        else
            Console.WriteLine("\tValidation error: " + args.Message);

    }
}
Chris McMillan
sumber
4
+1 meskipun harus diperbarui untuk menggunakan usingklausa untuk kelengkapan :)
IAbstrak
55
Jika Anda ingin membandingkan dengan file XSD tambahkan baris berikut ke kode di atas: settings.Schemas.Add ("YourDomainHere", "yourXSDFile.xsd");
Jeff Fol
5
Untuk mendapatkan Line # dan posisi # dari kesalahan cukup gunakan: args.Exception.LineNumber ... di ValidationCallBack
user610064
1
Bagaimana jika skema yang saya miliki tidak memiliki namespace?
pohon
1
Menggunakan lambda , IMHO yang lebih baik, kode yang lebih jelassettings.ValidationEventHandler += (o, args) => { errors = true; // More code };
Kiquenet
107

Cara yang lebih sederhana, jika Anda menggunakan .NET 3.5, adalah menggunakan XDocumentdan XmlSchemaSetmemvalidasi.

XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add(schemaNamespace, schemaFileName);

XDocument doc = XDocument.Load(filename);
string msg = "";
doc.Validate(schemas, (o, e) => {
    msg += e.Message + Environment.NewLine;
});
Console.WriteLine(msg == "" ? "Document is valid" : "Document invalid: " + msg);

Lihat dokumentasi MSDN untuk bantuan lebih lanjut.

nilai
sumber
2
Metode itu mengharuskan Anda mengetahui skema sebelumnya daripada mengambil skema inline dari xml.
Lankymart
ini berfungsi dengan baik tetapi menimbulkan kesalahan ketika dokumen xml berisi beberapa tag html seperti <catalog> katalog <i> baru </i> saya .... </catalog> dalam tag kasus html di atas seperti "<i>" menimbulkan masalah ketika ini adalah nilai "<catalog>" ... cara memvalidasinya
Anil Purswani
6
@AnilPurswani: Jika Anda ingin memasukkan HTML ke dalam dokumen XML, Anda harus membungkusnya dalam CDATA. <catalog><![CDATA[my <i> new </i> catalog....]]></catalog>adalah cara yang tepat untuk melakukan itu.
p0lar_bear
Sederhana dan elegan! Ini bekerja dengan sangat baik ketika memvalidasi terhadap set skema tetap (yang merupakan kasus kami, dan yang besar dengan banyak folder dan file). Saya sudah berpikir tentang melakukan caching XmlSchemaSet untuk digunakan kembali di antara panggilan ke Validator. Terima kasih banyak!
Adail Retamal
20

Berikut contoh memvalidasi file XML dan menghasilkan kesalahan atau peringatan yang sesuai.

using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;

public class Sample
{

    public static void Main()
    {
        //Load the XmlSchemaSet.
        XmlSchemaSet schemaSet = new XmlSchemaSet();
        schemaSet.Add("urn:bookstore-schema", "books.xsd");

        //Validate the file using the schema stored in the schema set.
        //Any elements belonging to the namespace "urn:cd-schema" generate
        //a warning because there is no schema matching that namespace.
        Validate("store.xml", schemaSet);
        Console.ReadLine();
    }

    private static void Validate(String filename, XmlSchemaSet schemaSet)
    {
        Console.WriteLine();
        Console.WriteLine("\r\nValidating XML file {0}...", filename.ToString());

        XmlSchema compiledSchema = null;

        foreach (XmlSchema schema in schemaSet.Schemas())
        {
            compiledSchema = schema;
        }

        XmlReaderSettings settings = new XmlReaderSettings();
        settings.Schemas.Add(compiledSchema);
        settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
        settings.ValidationType = ValidationType.Schema;

        //Create the schema validating reader.
        XmlReader vreader = XmlReader.Create(filename, settings);

        while (vreader.Read()) { }

        //Close the reader.
        vreader.Close();
    }

    //Display any warnings or errors.
    private static void ValidationCallBack(object sender, ValidationEventArgs args)
    {
        if (args.Severity == XmlSeverityType.Warning)
            Console.WriteLine("\tWarning: Matching schema not found.  No validation occurred." + args.Message);
        else
            Console.WriteLine("\tValidation error: " + args.Message);

    }
}

Contoh sebelumnya menggunakan file input berikut.

<?xml version='1.0'?>
<bookstore xmlns="urn:bookstore-schema" xmlns:cd="urn:cd-schema">
  <book genre="novel">
    <title>The Confidence Man</title>
    <price>11.99</price>
  </book>
  <cd:cd>
    <title>Americana</title>
    <cd:artist>Offspring</cd:artist>
    <price>16.95</price>
  </cd:cd>
</bookstore>

books.xsd

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="urn:bookstore-schema"
    elementFormDefault="qualified"
    targetNamespace="urn:bookstore-schema">

 <xsd:element name="bookstore" type="bookstoreType"/>

 <xsd:complexType name="bookstoreType">
  <xsd:sequence maxOccurs="unbounded">
   <xsd:element name="book"  type="bookType"/>
  </xsd:sequence>
 </xsd:complexType>

 <xsd:complexType name="bookType">
  <xsd:sequence>
   <xsd:element name="title" type="xsd:string"/>
   <xsd:element name="author" type="authorName"/>
   <xsd:element name="price"  type="xsd:decimal"/>
  </xsd:sequence>
  <xsd:attribute name="genre" type="xsd:string"/>
 </xsd:complexType>

 <xsd:complexType name="authorName">
  <xsd:sequence>
   <xsd:element name="first-name"  type="xsd:string"/>
   <xsd:element name="last-name" type="xsd:string"/>
  </xsd:sequence>
 </xsd:complexType>

</xsd:schema>
Soroush
sumber
18

secara pribadi saya lebih suka memvalidasi tanpa panggilan balik:

public bool ValidateSchema(string xmlPath, string xsdPath)
{
    XmlDocument xml = new XmlDocument();
    xml.Load(xmlPath);

    xml.Schemas.Add(null, xsdPath);

    try
    {
        xml.Validate(null);
    }
    catch (XmlSchemaValidationException)
    {
        return false;
    }
    return true;
}

(lihat posting Timiz0r di Validasi Skema XML Synchronous? .NET 3.5 )

FrankyHollywood
sumber
9
Callback memberi Anda beberapa informasi tambahan tentang baris mana di xml Anda yang tidak benar. Metode ini sangat biner, baik benar atau salah :)
FrankyHollywood
13

Saya telah melakukan semacam ini validasi otomatis dalam VB dan ini adalah bagaimana saya melakukannya (dikonversi ke C #):

XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags = settings.ValidationFlags |
                           Schema.XmlSchemaValidationFlags.ProcessSchemaLocation;
XmlReader XMLvalidator = XmlReader.Create(reader, settings);

Lalu saya berlangganan settings.ValidationEventHandleracara sambil membaca file.

Welbog
sumber