Ignorer les espaces de noms fournis lors de la validation de XML avec XSD

Contexte:

Nous allons construire une application qui permet à nos clients de fournir des données dans un prédéfinie (ie. nous ne contrôlons pas le format XML. Le XSD nous est fourni par un tiers, et nous nous attendons à recevoir un fichier XML qui passe la validation du schéma avant que nous ne le traitions.

Le Problème:

le XSD qui nous est fourni inclut un namespace par défaut et cible, ce qui signifie que si un client fournit un fichier XML qui n'inclut pas l'espace de noms, alors la validation passera. Nous ne voulons évidemment pas qu'ils fournissent des choses qui disent qu'ils passent mais ne devraient pas, mais la plus grande préoccupation est la masse de vérifications supplémentaires que nous devrons faire sur chaque élément si Je ne peux pas trouver une solution pour faire la validation XML.

Les Questions:

est - il possible de forcer .NET à effectuer une validation et d'ignorer l'espace de noms sur le XML fourni et XSD. c'est-à-dire d'une certaine façon "supposer" que l'espace de noms était attaché.

  1. est-il possible de supprimer les namespaces en mémoire, facilement et de manière fiable?
  2. Quelle est la meilleure pratique dans ces situations?

les Solutions que j'ai jusqu'à présent:

  1. Supprimer l'espace de noms de XSD chaque fois qu'il est mis à jour (ne devrait pas être très souvent. Cela ne va pas autour du fait que s'ils fournissent un namespace il sera toujours passé validation.
  2. Supprimer l'espace de noms de XSD, et trouver un moyen de supprimer l'espace de noms du XML entrant à chaque fois. Il semble que beaucoup de code pour effectuer quelque chose de simple.
  3. fait une pré-qualification sur le fichier XML avant qu'il ne soit validé pour s'assurer qu'il a l'espace de nom correct. Semble erroné de Les échouer en raison d'un namespace invalide si le contenu du fichier sont corrects.
  4. créer un duplicate XSD qui n'a pas d'espace de noms, cependant s'ils fournissent juste le mauvais espace de noms, ou un espace de noms différent, alors il passera quand même.

Exemple Xml:

<?xml version="1.0"?>
<xsd:schema version='3.09' elementFormDefault='qualified' attributeFormDefault='unqualified' id='blah' targetNamespace='urn:schemas-blah.com:blahExample' xmlns='urn:blah:blahExample' xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
...
</xsd:schema>

avec namespace qui est différent

 <?xml version="1.0" encoding="UTF-8" ?> 
<root xmlns="urn:myCompany.com:blahExample1" attr1="2001-03-03" attr2="google" >
...
</root>

sans namespace du tout.

 <?xml version="1.0" encoding="UTF-8" ?> 
<root attr1="2001-03-03" attr2="google" >
...
</root>
12
demandé sur Martin 2012-01-04 17:44:40

3 réponses

essayer de résoudre le même problème. J'ai trouvé ce que je pense être une solution assez propre. Pour plus de clarté, j'ai lancé une validation des paramètres d'entrée.

tout d'Abord, scénario: il y a un service web qui reçoit un fichier, qui est supposé être xml "bien formé" et valide contre un XSD. Bien sûr, nous ne faisons pas confiance à la "bonne humeur" ni au fait qu'il soit valide contre XSD que "nous savons" soit la bonne.

le code de ce service web la méthode est présentée ci-dessous, je pense qu'elle est explicite.

le principal point d'intérêt est l'ordre dans lequel les validations se produisent, vous ne Vérifiez pas l'espace de noms avant le chargement, vous vérifiez après, mais proprement.

j'ai décidé que je pouvais vivre avec une certaine gestion d'exception, car on s'attend à ce que la plupart des fichiers soient "bons" et parce que c'est la façon de traiter le cadre (donc je ne vais pas le combattre).

private DataTable xmlErrors;
[WebMethod]
public string Upload(byte[] f, string fileName) {
    string ret = "This will have the response";

    // this is the namespace that we want to use
    string xmlNs = "http://mydomain.com/ns/upload.xsd";

    // you could put a public url of xsd instead of a local file
    string xsdFileName = Server.MapPath("~") + "//" +"shiporder.xsd"; 

    // a simple table to store the eventual errors 
    // (more advanced ways possibly exist)
    xmlErrors = new DataTable("XmlErrors");
    xmlErrors.Columns.Add("Type");
    xmlErrors.Columns.Add("Message");

    try {
        XmlDocument doc = new XmlDocument(); // create a document

        // bind the document, namespace and xsd
        doc.Schemas.Add(xmlNs, xsdFileName); 

        // if we wanted to validate if the XSD has itself XML errors
        // doc.Schemas.ValidationEventHandler += 
        // new ValidationEventHandler(Schemas_ValidationEventHandler);

        // Declare the handler that will run on each error found
        ValidationEventHandler xmlValidator = 
            new ValidationEventHandler(Xml_ValidationEventHandler);

        // load the document 
        // will trhow XML.Exception if document is not "well formed"
        doc.Load(new MemoryStream(f));

        // Check if the required namespace is present
        if (doc.DocumentElement.NamespaceURI == xmlNs) {

            // Validate against xsd 
            // will call Xml_ValidationEventHandler on each error found
            doc.Validate(xmlValidator);

            if (xmlErrors.Rows.Count == 0) {
                ret = "OK";
            } else {
                // return the complete error list, this is just to proove it works
                ret = "File has " + xmlErrors.Rows.Count + " xml errors ";
                ret += "when validated against our XSD.";
            }
        } else {
            ret = "The xml document has incorrect or no namespace.";                
        }
    } catch (XmlException ex) {
        ret = "XML Exception: probably xml not well formed... ";
        ret += "Message = " + ex.Message.ToString();
    } catch (Exception ex) {
        ret = "Exception: probably not XML related... "
        ret += "Message = " + ex.Message.ToString();
    }
    return ret;
}

private void Xml_ValidationEventHandler(object sender, ValidationEventArgs e) {
    xmlErrors.Rows.Add(new object[] { e.Severity, e.Message });
}

Maintenant, le xsd aurait quelque chose comme:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="shiporder"
    targetNamespace="http://mydomain.com/ns/upload.xsd"
    elementFormDefault="qualified"
    xmlns="http://mydomain.com/ns/upload.xsd"
    xmlns:mstns="http://mydomain.com/ns/upload.xsd"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
    <xs:simpleType name="stringtype">
      <xs:restriction base="xs:string"/>
    </xs:simpleType>
    ...
    </xs:schema>

Et le "bon" XML serait quelque chose comme:

<?xml version="1.0" encoding="utf-8" ?>
<shiporder orderid="889923"  xmlns="http://mydomain.com/ns/upload.xsd">
  <orderperson>John Smith</orderperson>
  <shipto>
    <names>Ola Nordmann</names>
    <address>Langgt 23</address>

j'ai testé, "mauvais format XML"," entrée invalide selon XSD","espace de nom incorrect".

références:

Lire du memorystream

en Essayant d'éviter de gestion des exceptions la vérification de wellformness

valider contre XSD, attraper les erreurs

Intéressant post sur inline de la validation du schéma


Salut Martin, le commentaire sction est trop court pour ma réponse, donc je vais donner ici, il peut ou pas être une réponse complète, nous allons l'améliorer :)

j'ai fait les tests suivants:

  • Test: xmlns= "blaa"
  • résultat: le fichier est rejeté à cause d'un mauvais namespace.
  • Test: xmlns="http://mydomain.com/ns/upload.xsd" et xmlns: a="blaa" et les éléments avaient "un:someElement"
  • Résultat: Le fichier retunrs d'erreur disant qu'il ne s'attendait pas ": someElement"
  • Test: xmlns="http://mydomain.com/ns/upload.xsd" et xmlns:a="alpage blaa" et les éléments "someElement" avec un attribut nécessaire manquant
  • Résultat: Le fichier d'erreur s'affiche en disant que l'attribut est absent

stratégie suivi (ce que je préfère) était, si le document n'est pas conforme, alors n'acceptez pas, mais donnez quelques informations sur la raison (par exemple. "mal de l'espace de noms").

Cette stratégie semble contraire à ce que vous avez déclaré précédemment:

cependant, si un client manque la déclaration namespace dans leur XML soumis, je voudrais dire que nous pouvons encore la valider. Je ne veux pas juste dire "Tu as foiré, maintenant répare-le!"

dans ce cas, il semble que vous pouvez simplement ignorer l'espace de noms défini dans XML. Pour ce faire, vous sauteriez la validation de namespace correct:

    ...
    // Don't Check if the required namespace is present
    //if (doc.DocumentElement.NamespaceURI == xmlNs) {

        // Validate against xsd 
        // will call Xml_ValidationEventHandler on each error found
        doc.Validate(xmlValidator);

        if (xmlErrors.Rows.Count == 0) {
            ret = "OK - is valid against our XSD";
        } else {
            // return the complete error list, this is just to proove it works
            ret = "File has " + xmlErrors.Rows.Count + " xml errors ";
            ret += "when validated against our XSD.";
        }
    //} else {
    //    ret = "The xml document has incorrect or no namespace.";                
    //}
    ...



d'Autres idées...

dans une ligne parallèle de pensée, pour remplacer l'espace de noms fourni par le vôtre, vous pourriez peut-être définir doc.DocumentElement.NamespaceURI = "mySpecialNamespace" remplaçant ainsi le namepsace de l'élément racine.

Référence:

add-plusieurs espaces de noms-de-la-root-element

6
répondu Luís Osório 2017-05-23 12:18:14

le point entier derrière un schéma XSD est qu'il rend XML non typé en XML fortement typé.

un type XML peut être défini comme la combinaison de node-name et namespace.

si quelqu'un vous envoie XML sans espace de noms alors malgré les intentions le XML ne se réfère pas aux types tels que définis par le schéma XSD.

du point de vue de la validation XML, le XML est valide aussi longtemps que

  1. il est bien formé
  2. Il confirme à toute définition XML dactylographiée, telle que spécifiée par l'attribut xmlns
0
répondu tom redfern 2012-01-04 13:55:41

j'utilise XmlSchemaValidationFlags.Drapeau ReportValidationWarnings. Sinon, xml avec namespace inconnu (ou sans namespace) passera silencieusement la validation.

public static void Validate(string xml, string schemaPath)
{
    //oops: no ValidationFlag property, cant use linq
    //var d = XDocument.Parse(xml);
    //var sc = new XmlSchemaSet();
    //sc.Add(null, schemaPath);
    //sc.CompilationSettings.EnableUpaCheck = false;
    //d.Validate(sc, null);

    XmlReaderSettings Xsettings = new XmlReaderSettings();
    Xsettings.Schemas.Add(null, schemaPath);
    Xsettings.ValidationType = ValidationType.Schema;
    Xsettings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
    Xsettings.Schemas.CompilationSettings.EnableUpaCheck = false;
    Xsettings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);

    XmlReader reader = XmlReader.Create(new StringReader(xml), Xsettings);
    while (reader.Read())
    {
    }
}

private static void ValidationCallBack(object sender, ValidationEventArgs e)
{
    if (e.Severity == XmlSeverityType.Warning)
        throw new Exception(string.Format("No validation occurred. {0}", e.Message));
    else
        throw new Exception(string.Format("Validation error: {0}", e.Message));
}
0
répondu Alexey Obukhov 2016-08-26 16:16:45