2009-04-03 4 views
4

Ich arbeite mit einigen XML-Snippets, die Elemente in der XML-Form bilden. Ich habe das Schema, aber ich kann diese Dateien nicht validieren, weil sie keine vollständigen XML-Dokumente sind. Diese Snippets werden mit den erforderlichen übergeordneten Elementen umschlossen, um gültiges XML zu bilden, wenn sie in anderen Tools verwendet werden, so dass ich nicht viele Optionen habe, um sie in gültiges XML umzuwandeln oder das Schema zu ändern.Validierung von XML-Knoten, nicht das gesamte Dokument

Ist es möglich, ein Element und nicht das gesamte Dokument zu validieren? Wenn nicht, welche Workarounds könnten vorgeschlagen werden?

Ich arbeite in C# mit .NET 2.0 Framework.

+0

Ich bin nicht sicher, wie Sie 'SelectSingleNode' verwenden könnten, wenn Sie nicht den Wurzelknoten des' XmlDocument' verwenden können, in den Sie Ihr Xml laden müssten, was fehlschlagen würde, wenn es nicht gültig wäre. Es lässt mich denken, dass Sie 'XPath' nicht verwenden können, wenn Ihr Dokument selbst nicht gültig ist. Oder gibt es eine Möglichkeit, dies zu tun? –

Antwort

4

Ich hatte ein ähnliches Problem, wo ich nur Teile meines XML-Dokuments validieren konnte. Ich kam hierher mit dieser Methode auf:

private void ValidateSubnode(XmlNode node, XmlSchema schema) 
{ 
    XmlTextReader reader = new XmlTextReader(node.OuterXml, XmlNodeType.Element, null); 

    XmlReaderSettings settings = new XmlReaderSettings(); 
    settings.ConformanceLevel = ConformanceLevel.Fragment; 
    settings.Schemas.Add(schema); 
    settings.ValidationType = ValidationType.Schema; 
    settings.ValidationEventHandler += new ValidationEventHandler(XSDValidationEventHandler); 

    using (XmlReader validationReader = XmlReader.Create(reader, settings)) 
    {  
     while (validationReader.Read()) 
     { 
     } 
    } 
} 

private void XSDValidationEventHandler(object sender, ValidationEventArgs args) 
{ 
    errors.AppendFormat("XSD - Severity {0} - {1}", 
         args.Severity.ToString(), args.Message); 
} 

Grundsätzlich gibt ich ihm ein XmlNode (was ich aus dem gesamten XmlDocument wähle mittels .SelectSingleNode) und ein XML-Schema, das ich aus einer eingebetteten Ressource XSD lade innen meine App. Alle Überprüfungsfehler, die auftreten könnten, werden in einen String Builder für "Fehler" eingefügt, den ich dann am Ende auslese, um zu sehen, ob irgendwelche Fehler aufgezeichnet wurden oder nicht.

Works für mich - die Leistung kann variieren :-)

+0

Diese Lösung funktioniert ganz gut. In der Tat sieht dies auffallend ähnlich zu der Validierung, die ich gerade für Dokumente habe. Ich wusste nicht, dass es auch auf einzelne Knoten angewendet werden könnte. Rückblickend nehme ich an, dass die Wurzel selbst ein Knoten ist. – ipwnponies

+0

Danke, Marc! Das hat mir auch sehr geholfen. – Kizz

+0

Marc, könnten Sie diese Antwort so bearbeiten, dass sie 'XmlTextReader' nicht verwendet und' using' Blöcke verwendet? Ich habe gerade gesehen, dass dieser Code kopiert/eingefügt wurde. –

0

Sie können einen speziellen Namespace-Alias ​​verwenden, um die Elemente zu kennzeichnen, die Sie validieren möchten, und dann nur ein Schema für diesen Namespace-Alias ​​hinzufügen, aber nicht für andere. Auf diese Weise werden nur die Elemente mit Ihrem speziellen Namespacepräfix validiert.

+0

Von dem, was ich verstehe, wäre dies nicht geeignet, da es zum Bearbeiten/Erstellen von Schemas erforderlich ist. Ich kann das Schema nicht ändern, da es ein Protokoll ist, das von anderen auf einer jährlichen Basis verwendet und aktualisiert wird. Ich erstelle nur ein internes Werkzeug, deshalb muss die Wartung auf ein Minimum beschränkt werden. – ipwnponies

2

Es gibt eine XmlDocument.Validate Methode, die ein als Argument akzeptiert und nur diesen Knoten validiert. Das könnte sein, was Sie suchen ...

+0

Leider habe ich ab sofort keinen Zugriff auf mein Projekt, daher kann ich dies nicht bestätigen. Aber nachdem ich MSDN gelesen habe, scheint es, dass ich genau danach gesucht habe. Die ganze Zeit habe ich unter XmlSchema gesucht ... – ipwnponies

+0

Das funktioniert nicht. Der zu validierende Knoten muss in der richtigen Tiefe sein. Diese Methode wäre nützlich, wenn Sie Ihre XML-Datei teilweise validieren möchten. Ich habe zunächst keine gültige XML-Datei. – ipwnponies

0

Es scheint nicht möglich zu tun, was ich tun möchte. Meine aktuelle Arbeit besteht darin, ein leeres XML-Dokument zu erstellen. Dann ersetzen Sie das gewünschte Element durch mein Snippet. Von da an glaube ich, dass die Validate-Methode dann praktikabel wäre. Die dynamische Erstellung dieses Templates scheint jedoch eine weitere entmutigende Aufgabe zu sein. Es scheint keine einfache Möglichkeit zu geben, ein "Skelett" -Dokument zu erstellen.

+0

Ich denke, XSLT könnte nützlich sein. Sehen Sie sich meine neue Antwort für einige Vorschläge an. – MartinStettner

1

Ok, hier ist ein anderer Ansatz:

Sie könnten Ihre Schemadatei mit Hilfe einer XSLT-Transformation in ein neues Schema umwandeln, die Ihre Schnipsel Elemente als Wurzel hat. Sagen Sie Ihre ursprüngliche Schema wäre

<xs:schema id="MySchema" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xs:element name="RootElement"> 
    <xs:complexType> 
     <xs:sequence> 
     <xs:element name="NestedElement"> 
      <xs:complexType> 
      <xs:attribute name="Name" type="xs:string" use="required"/> 
      </xs:complexType> 
     </xs:element> 
     </xs:sequence> 
    </xs:complexType> 
    </xs:element> 
</xs:schema> 

Sie Schnipsel vom Typ haben NestedElement, die Sie überprüfen möchten:

<NestedElement Name1="Name1" /> 

Dann Sie eine XSLT-Vorlage verwenden könnte wie

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="xs:element[@name='NestedElement']" 
       xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xs:schema id="MySchema"> 
     <xsl:copy-of select="."/> 
    </xs:schema> 
    </xsl:template> 
</xsl:stylesheet> 

a zu erstellen neues Schema, das NestedElement als root hat. Das resultierende Schema würde aussehen wie

<xs:schema id="MySchema" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xs:element name="NestedElement"> 
    <xs:complexType> 
     <xs:attribute name="Name" type="xs:string" use="required" /> 
    </xs:complexType> 
    </xs:element> 
</xs:schema> 

Sie können dann einen Schnipsel Dokument gegen dieses neue Schema validieren einen Code wie

XmlSchema schema; 
using (MemoryStream stream = new MemoryStream()) 
using (FileStream fs = new FileStream("MySchema.xsd", FileMode.Open)) 
using(XmlReader reader = XmlReader.Create(fs)) { 
    XslCompiledTransform transform = new XslCompiledTransform(); 
    transform.Load("SchemaTransform.xslt"); 
    transform.Transform(reader, null, stream); 
    stream.Seek(0, SeekOrigin.Begin); 
    schema = XmlSchema.Read(stream, null); 
} 
XmlDocument doc = new XmlDocument(); 
doc.Schemas.Add(schema); 
doc.Load("rootelement.xml"); 
doc.Validate(ValidationHandler); 

MySchema.xsd verwendet, ist das ursprüngliche Schema, SchemaTransform.xslt die Transformation (wie oben dargestellt) rootelement.xml ist ein XML-Dokument, das einen einzelnen Snippet-Knoten enthält.

+0

Dies ist eine sehr elegante Lösung. Aber es gibt eine Sache, die mich davon abhält, sie zu benutzen. Die Transformation erfordert, dass das Wissen über das 'NestedElement' bekannt ist. Dies ist ein Problem, da das Schema möglicherweise von Dritten aktualisiert wird und eine Aktualisierung/Wartung des xslt erforderlich ist. – ipwnponies

+0

Sie könnten den Elementnamen (z. B. "NestedElememt") zu einem Parameter machen und ihn aus dem Element der obersten Ebene des Snippets innerhalb des Codes lesen. Dann würde es auch für mehrere Schnipsel-Elemente funktionieren ... – MartinStettner

+0

Wenn Sie Zeit haben, können Sie vielleicht den "Fütterungs" -Parameter-Trick demonstrieren. Ich habe buchstäblich 3-4 Stunden damit verschwendet und bin nirgendwohin gekommen. Eigentlich ist die Eingabe des Parameters einfach, der Trick besteht darin, ihn in XSLT 1.0 zu verwenden: http://StackOverflow.com/questions/6117460/xsl-how-to-use-parameter-inside-match, aber ich bin nie irgendwo hingekommen, nämlich Die Vorlage hat nie mit dem übereingestimmt, was ich wollte. Gehen Sie zu string.Replace alles für den Moment, wie das ist lächerlich. +1 für die Lösung obwohl. –

0

ich hatte das gleiche Problem. Auch hier nach einer Lösung gefragt. Ich habe einen Workaround gefunden.

Das Problem ist, dass nur Root-Elemente validiert werden können. Also ... ich das Schema IN MEMORY bearbeiten und das Element/Typ hinzufügen, an die Wurzel

public static void AddElementToSchema(XmlSchema xmlSchema, string elementName, string elementType, string xmlNamespace) 
{ 
    XmlSchemaElement testNode = new XmlSchemaElement(); 
    testNode.Name = elementName; 
    testNode.Namespaces.Add("", xmlNamespace); 
    testNode.SchemaTypeName = new XmlQualifiedName(elementType, xmlNamespace); 
    xmlSchema.Items.Add(testNode); 
    xmlSchema.Compile(XMLValidationEventHandler); 
} 

Nur ein paar Zeilen zu bestätigen und Sie müssen alle XSD-Dateien :) Mit dieser einfachen Änderung nicht ändern oder ergänzen Wenn Sie Ihr speicherinternes Schema verwenden, können Sie das Fragment mit demselben Code validieren, den Sie zum Validieren eines vollständigen Dokuments verwenden. Stellen Sie sicher, dass das Wurzelelement des zu validierenden Fragments den Namespace enthält. :)

Verwandte Themen