Domanda

Ecco il mio primo tentativo di convalidare XML con XSD.

Il file XML da convalidare:

<?xml version="1.0" encoding="utf-8" ?>
<config xmlns="Schemas" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="config.xsd">
  <levelVariant>
    <filePath>SampleVariant</filePath>
  </levelVariant>
  <levelVariant>
    <filePath>LegendaryMode</filePath>
  </levelVariant>
  <levelVariant>
    <filePath>AmazingMode</filePath>
  </levelVariant>
</config>

Il XSD, che si trova in "Schemi / config.xsd" relativo al file XML da convalidare:

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="config">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="levelVariant">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="filePath" type="xs:anyURI">
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

In questo momento, voglio solo per convalidare il file XML esattamente come appare attualmente. Una volta che ho capito questo meglio, io espandersi più. Ho davvero bisogno di così tante linee di qualcosa di semplice come il file XML nella sua forma attuale?

Il codice di convalida in C #:

        public void SetURI(string uri)
        {
            XElement toValidate = XElement.Load(Path.Combine(PATH_TO_DATA_DIR, uri) + ".xml");

// begin confusion

       // exception here
       string schemaURI = toValidate.Attributes("xmlns").First().ToString() 
                              + toValidate.Attributes("xsi:noNamespaceSchemaLocation").First().ToString();
        XmlSchemaSet schemas = new XmlSchemaSet();
        schemas.Add(null, schemaURI);

        XDocument toValidateDoc = new XDocument(toValidate);
        toValidateDoc.Validate(schemas, null);
// end confusion

            root = toValidate;
        }

L'esecuzione del codice di cui sopra dà questa eccezione:

The ':' character, hexadecimal value 0x3A, cannot be included in a name.

Qualunque illuminazione sarebbe apprezzato.

È stato utile?

Soluzione

Invece di utilizzare il XDocument.Validate metodo di estensione, vorrei usare un XmlReader che può essere configurato per elaborare uno schema inline tramite XmlReaderSettings . Si potrebbe fare qualche cosa come il seguente codice.

public void VerifyXmlFile(string path)
{
    // configure the xmlreader validation to use inline schema.
    XmlReaderSettings config = new XmlReaderSettings();
    config.ValidationType = ValidationType.Schema;
    config.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
    config.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
    config.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
    config.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);

    // Get the XmlReader object with the configured settings.
    XmlReader reader = XmlReader.Create(path, config);

    // Parsing the file will cause the validation to occur.
    while (reader.Read()) ;

}

private void ValidationCallBack(object sender, ValidationEventArgs vea)
{
    if (vea.Severity == XmlSeverityType.Warning)
        Console.WriteLine(
            "\tWarning: Matching schema not found.  No validation occurred. {0}",
            vea.Message);
    else
        Console.WriteLine("\tValidation error: {0}", vea.Message);

}

Il codice sopra presuppone quanto segue utilizzando le istruzioni.

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

Solo per mantenere questo semplice Non tornai un boolean o un insieme di errori di convalida, si potrebbe facilmente modificare questo per farlo.

Nota: ho modificato il tuo config.xml e config.xsd di farli convalidare. Questi sono i cambiamenti che ho fatto.

config.xsd:

<xs:element maxOccurs="unbounded" name="levelVariant">

config.xml:

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="config.xsd">

Altri suggerimenti

In seguito è fuori di un campione di lavoro:

Utilizzo:

XMLValidator val = new XMLValidator();
if (!val.IsValidXml(File.ReadAllText(@"d:\Test2.xml"), @"D:\Test2.xsd"))
   MessageBox.Show(val.Errors);

Classe:

public class CXmlValidator
{
    private int nErrors = 0;
    private string strErrorMsg = string.Empty;
    public string Errors { get { return strErrorMsg; } }
    public void ValidationHandler(object sender, ValidationEventArgs args)
    {
        nErrors++;
        strErrorMsg = strErrorMsg + args.Message + "\r\n";
    }

    public bool IsValidXml(string strXml/*xml in text*/, string strXsdLocation /*Xsd location*/)
    {
        bool bStatus = false;
        try
        {
            // Declare local objects
            XmlTextReader xtrReader = new XmlTextReader(strXsdLocation);
            XmlSchemaCollection xcSchemaCollection = new XmlSchemaCollection();
            xcSchemaCollection.Add(null/*add your namespace string*/, xtrReader);//Add multiple schemas if you want.

            XmlValidatingReader vrValidator = new XmlValidatingReader(strXml, XmlNodeType.Document, null);
            vrValidator.Schemas.Add(xcSchemaCollection);

            // Add validation event handler
            vrValidator.ValidationType = ValidationType.Schema;
            vrValidator.ValidationEventHandler += new ValidationEventHandler(ValidationHandler);

            //Actual validation, read conforming the schema.
            while (vrValidator.Read()) ;

            vrValidator.Close();//Cleanup

            //Exception if error.
            if (nErrors > 0) { throw new Exception(strErrorMsg); }
            else { bStatus = true; }//Success
        }
        catch (Exception error) { bStatus = false; }

        return bStatus;
    }
}

Il codice sopra convalida seguente codice XML (CODE3) contro XSD (code4).

<!--CODE 3 - TEST1.XML-->
<address xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Test1.xsd"> 
<name>My Name</name>
<street>1, My Street Address</street>
<city>Far</city>
<country>Mali</country>
</address>

<!--CODE 4 - TEST1.XSD-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="address">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

Nel convalidare contro il tuo XML / XSD ricevo degli errori diversa dalla vostra; Credo che questo possa aiutarti a continuare (aggiungere / rimuovere elementi XML) da qui:

Errori

Si può anche provare il processo inverso; provare a generare lo schema XML dal vostro e confrontarlo con il vostro XSD attuale - vedere la differenza; e il modo più semplice per farlo è quello di utilizzare generare schema utilizzando VS IDE. In seguito è come si farebbe che:

Crea XSD da XML

Spero che questo aiuti.

- EDIT -

Questa è disponibile su richiesta di Giovanni, si prega di consultare il codice aggiornato con metodi non deprecate:

public bool IsValidXmlEx(string strXmlLocation, string strXsdLocation)
{
    bool bStatus = false;
    try
    {
        // Declare local objects
        XmlReaderSettings rs = new XmlReaderSettings();
        rs.ValidationType = ValidationType.Schema;
        rs.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation | XmlSchemaValidationFlags.ReportValidationWarnings;
        rs.ValidationEventHandler += new ValidationEventHandler(rs_ValidationEventHandler);
        rs.Schemas.Add(null, XmlReader.Create(strXsdLocation));

        using (XmlReader xmlValidatingReader = XmlReader.Create(strXmlLocation, rs))
        { while (xmlValidatingReader.Read()) { } }

        ////Exception if error.
        if (nErrors > 0) { throw new Exception(strErrorMsg); }
        else { bStatus = true; }//Success
    }
    catch (Exception error) { bStatus = false; }

    return bStatus;
}

void rs_ValidationEventHandler(object sender, ValidationEventArgs e)
{
    if (e.Severity == XmlSeverityType.Warning) strErrorMsg += "WARNING: " + Environment.NewLine;
    else strErrorMsg += "ERROR: " + Environment.NewLine;
    nErrors++;
    strErrorMsg = strErrorMsg + e.Exception.Message + "\r\n";
}

Utilizzo:

if (!val.IsValidXmlEx(@"d:\Test2.xml", @"D:\Test2.xsd"))
                MessageBox.Show(val.Errors);
            else
                MessageBox.Show("Success");

test2.xml

<?xml version="1.0" encoding="utf-8" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Test2.xsd">
  <levelVariant>
    <filePath>SampleVariant</filePath>
  </levelVariant>
  <levelVariant>
    <filePath>LegendaryMode</filePath>
  </levelVariant>
  <levelVariant>
    <filePath>AmazingMode</filePath>
  </levelVariant>
</config>

Test2.XSD (generato da VS IDE)

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="config">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="levelVariant">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="filePath" type="xs:anyURI">
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Questa è garantito il funzionamento!

Il codice per estrarre la posizione dello schema sembra strano. Perché si ottiene il valore di attributo xmlns e concatenare con il valore del attributo xsi: noNamespaceSchemaLocation? L'eccezione è causato dal fatto che non è possibile specificare un prefisso in una chiamata a Attributi; è necessario specificare il XNamespace desiderato.

Prova questo (non testata):

// Load document
XDocument doc = XDocument.Load("file.xml");

// Extract value of xsi:noNamespaceSchemaLocation
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
string schemaURI = (string)doc.Root.Attribute(xsi + "noNamespaceSchemaLocation");

// Create schema set
XmlSchemaSet schemas = new XmlSchemaSet();
schemas.Add("Schemas", schemaURI);

// Validate
doc.Validate(schemas, (o, e) =>
                      {
                          Console.WriteLine("{0}", e.Message);
                      });
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top