Validating xml nodes, not the entire document

隐身守侯 提交于 2019-12-17 19:07:09

问题


I'm working with some xml 'snippets' that form elements down the xml. I have the schema but I cannot validate these files because they are not complete xml documents. These snippets are wrapped with the necessary parent elements to form valid xml when they are used in other tools so I don't have much option in making them into valid xml or in changing the schema.

Is it possible to validate an element, rather than the whole document? If not, what workarounds could be suggested?

I'm working in C# with .NET 2.0 framework.


回答1:


I had a similar problem where I could only validate parts of my XML document. I came up with this method here:

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

Basically, I pass it an XmlNode (which I select from the entire XmlDocument by means of .SelectSingleNode), and an XML schema which I load from an embedded resource XSD inside my app. Any validation errors that might occur are being stuffed into a "errors" string builder, which I then read out at the end, to see if there were any errors recorded, or not.

Works for me - your mileage may vary :-)




回答2:


There is a XmlDocument.Validate method that takes an XmlNode as argument an validates only this node. That may be what you're looking for ...




回答3:


Ok, here's another approach:

You could transform your schema file using an XSLT transformation into a new schema that has your snippet elements as root. Say your original schema would be

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

You have snippets of type NestedElement that you want to validate:

<NestedElement Name1="Name1" />

Then you could use an XSLT template like

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

To create a new schema that has NestedElement as root. The resulting schema would look like

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

You can then validate a snippet document against this new schema using a code like

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 is the original schema, SchemaTransform.xslt is the transformation (as shown above), rootelement.xml is an XML document containing a single snippet node.




回答4:


You can use a special namespace alias to earmark the elements you want to validate and then only add schema for that namespace alias but not for others. This way only those elements with your special namespace prefix will get validated.




回答5:


It doesn't not seem possible to do what I aspire to do. My current work around is to create a blank template xml document. Then replace the desired element with my snippet. From there, I believe the Validate method would then be viable. But to create this template dynamically seems to be another daunting task in its own right. There doesn't seem to be any easy way to create a 'skeleton' document.




回答6:


I had the same problem. Even asked here for solution. I have found a workaround.

The problem is that only root elements can be validated. So... I edit the scheme IN MEMORY and add the element/type to validate to the root

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

Just a couple of lines and you must not modify or add any XSD files :) With this simple change to your in-memory schema, you can validate the fragment with the same code you use to validate a full document. Just be sure that the root element of the fragment to validate includes the namespace. :)



来源:https://stackoverflow.com/questions/715626/validating-xml-nodes-not-the-entire-document

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!