views:

780

answers:

5

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.

A: 

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.

zvolkov
From what I understand, this would not be suitable as it requires to editing/creating schemas. I cannot change the schema because it is a protocol that is used and updated by others on a yearly basis. I am only creating an internal tool, so maintenance must be kept to a minimum.
ipwnponies
+2  A: 

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

MartinStettner
Unfortunately, I don't have access to my project as of now, so I cannot verify this. But from reading MSDN, it does seem that this is what I was looking for. All this time, I've been looking under XmlSchema...
ipwnponies
This does not work. The node to be validated, has to be at the correct 'depth'. This method would be useful for if you wanted to partially validate your xml file. I don't have a valid xml file to begin with.
ipwnponies
A: 

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.

ipwnponies
I think, XSLT might be of use. Look at my new answer for some suggestions
MartinStettner
A: 

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"&gt;
  <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"&gt;
  <xsl:template match="xs:element[@name='NestedElement']"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;
    <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"&gt;
  <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.

MartinStettner
This is a very elegant solution. But there is one thing keeping me from using it. The transform requires that knowledge of the 'NestedElement' be known. This is an issue as there may be updates to the schema by third parties and that would require an update/maintenance to the xslt.
ipwnponies
You could make the element name (i.e. 'NestedElememt') a parameter and read it from the top level element of the snippet inside the code. Then it would also work for multiple snippet elements ...
MartinStettner
+1  A: 

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

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

Marc

marc_s
This solution works quite well. In fact, this looks strikingly similar to the validation I have in place right now for documents. I did not know it could be applied to individual nodes as well. Looking back, I suppose the root is a node in itself.
ipwnponies