2016-08-03 10:59:49 +00:00
//------------------------------------------------------------------------------
// <copyright file="XmlDocumentValidator.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
2017-08-21 15:34:15 +00:00
// <owner current="true" primary="true">Microsoft</owner>
2016-08-03 10:59:49 +00:00
//------------------------------------------------------------------------------
using System ;
using System.Text ;
using System.Collections ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.Xml ;
using System.Xml.Schema ;
using System.Xml.XPath ;
using System.Globalization ;
using System.Security ;
using System.Security.Policy ;
using System.Security.Permissions ;
using System.Reflection ;
using System.Runtime.Versioning ;
namespace System.Xml {
internal sealed class DocumentSchemaValidator : IXmlNamespaceResolver {
XmlSchemaValidator validator ;
XmlSchemaSet schemas ;
XmlNamespaceManager nsManager ;
XmlNameTable nameTable ;
//Attributes
ArrayList defaultAttributes ;
XmlValueGetter nodeValueGetter ;
XmlSchemaInfo attributeSchemaInfo ;
//Element PSVI
XmlSchemaInfo schemaInfo ;
//Event Handler
ValidationEventHandler eventHandler ;
ValidationEventHandler internalEventHandler ;
//Store nodes
XmlNode startNode ;
XmlNode currentNode ;
XmlDocument document ;
//List of nodes for partial validation tree walk
XmlNode [ ] nodeSequenceToValidate ;
bool isPartialTreeValid ;
bool psviAugmentation ;
bool isValid ;
//To avoid SchemaNames creation
private string NsXmlNs ;
private string NsXsi ;
private string XsiType ;
private string XsiNil ;
public DocumentSchemaValidator ( XmlDocument ownerDocument , XmlSchemaSet schemas , ValidationEventHandler eventHandler ) {
this . schemas = schemas ;
this . eventHandler = eventHandler ;
document = ownerDocument ;
this . internalEventHandler = new ValidationEventHandler ( InternalValidationCallBack ) ;
this . nameTable = document . NameTable ;
nsManager = new XmlNamespaceManager ( nameTable ) ;
Debug . Assert ( schemas ! = null & & schemas . Count > 0 ) ;
nodeValueGetter = new XmlValueGetter ( GetNodeValue ) ;
psviAugmentation = true ;
//Add common strings to be compared to NameTable
NsXmlNs = nameTable . Add ( XmlReservedNs . NsXmlNs ) ;
NsXsi = nameTable . Add ( XmlReservedNs . NsXsi ) ;
XsiType = nameTable . Add ( "type" ) ;
XsiNil = nameTable . Add ( "nil" ) ;
}
public bool PsviAugmentation {
get { return psviAugmentation ; }
set { psviAugmentation = value ; }
}
public bool Validate ( XmlNode nodeToValidate ) {
XmlSchemaObject partialValidationType = null ;
XmlSchemaValidationFlags validationFlags = XmlSchemaValidationFlags . AllowXmlAttributes ;
Debug . Assert ( nodeToValidate . SchemaInfo ! = null ) ;
startNode = nodeToValidate ;
switch ( nodeToValidate . NodeType ) {
case XmlNodeType . Document :
validationFlags | = XmlSchemaValidationFlags . ProcessIdentityConstraints ;
break ;
case XmlNodeType . DocumentFragment :
break ;
case XmlNodeType . Element : //Validate children of this element
IXmlSchemaInfo schemaInfo = nodeToValidate . SchemaInfo ;
XmlSchemaElement schemaElement = schemaInfo . SchemaElement ;
if ( schemaElement ! = null ) {
if ( ! schemaElement . RefName . IsEmpty ) { //If it is element ref,
partialValidationType = schemas . GlobalElements [ schemaElement . QualifiedName ] ; //Get Global element with correct Nillable, Default etc
}
else { //local element
partialValidationType = schemaElement ;
}
//Verify that if there was xsi:type, the schemaElement returned has the correct type set
Debug . Assert ( schemaElement . ElementSchemaType = = schemaInfo . SchemaType ) ;
}
else { //Can be an element that matched xs:any and had xsi:type
partialValidationType = schemaInfo . SchemaType ;
if ( partialValidationType = = null ) { //Validated against xs:any with pc= lax or skip or undeclared / not validated element
if ( nodeToValidate . ParentNode . NodeType = = XmlNodeType . Document ) {
//If this is the documentElement and it has not been validated at all
nodeToValidate = nodeToValidate . ParentNode ;
}
else {
partialValidationType = FindSchemaInfo ( nodeToValidate as XmlElement ) ;
if ( partialValidationType = = null ) {
throw new XmlSchemaValidationException ( Res . XmlDocument_NoNodeSchemaInfo , null , nodeToValidate ) ;
}
}
}
}
break ;
case XmlNodeType . Attribute :
if ( nodeToValidate . XPNodeType = = XPathNodeType . Namespace ) goto default ;
partialValidationType = nodeToValidate . SchemaInfo . SchemaAttribute ;
if ( partialValidationType = = null ) { //Validated against xs:anyAttribute with pc = lax or skip / undeclared attribute
partialValidationType = FindSchemaInfo ( nodeToValidate as XmlAttribute ) ;
if ( partialValidationType = = null ) {
throw new XmlSchemaValidationException ( Res . XmlDocument_NoNodeSchemaInfo , null , nodeToValidate ) ;
}
}
break ;
default :
throw new InvalidOperationException ( Res . GetString ( Res . XmlDocument_ValidateInvalidNodeType , null ) ) ;
}
isValid = true ;
CreateValidator ( partialValidationType , validationFlags ) ;
if ( psviAugmentation ) {
if ( schemaInfo = = null ) { //Might have created it during FindSchemaInfo
schemaInfo = new XmlSchemaInfo ( ) ;
}
attributeSchemaInfo = new XmlSchemaInfo ( ) ;
}
ValidateNode ( nodeToValidate ) ;
validator . EndValidation ( ) ;
return isValid ;
}
public IDictionary < string , string > GetNamespacesInScope ( XmlNamespaceScope scope ) {
IDictionary < string , string > dictionary = nsManager . GetNamespacesInScope ( scope ) ;
if ( scope ! = XmlNamespaceScope . Local ) {
XmlNode node = startNode ;
while ( node ! = null ) {
switch ( node . NodeType ) {
case XmlNodeType . Element :
XmlElement elem = ( XmlElement ) node ;
if ( elem . HasAttributes ) {
XmlAttributeCollection attrs = elem . Attributes ;
for ( int i = 0 ; i < attrs . Count ; i + + ) {
XmlAttribute attr = attrs [ i ] ;
if ( Ref . Equal ( attr . NamespaceURI , document . strReservedXmlns ) ) {
if ( attr . Prefix . Length = = 0 ) {
// xmlns='' declaration
if ( ! dictionary . ContainsKey ( string . Empty ) ) {
dictionary . Add ( string . Empty , attr . Value ) ;
}
}
else {
// xmlns:prefix='' declaration
if ( ! dictionary . ContainsKey ( attr . LocalName ) ) {
dictionary . Add ( attr . LocalName , attr . Value ) ;
}
}
}
}
}
node = node . ParentNode ;
break ;
case XmlNodeType . Attribute :
node = ( ( XmlAttribute ) node ) . OwnerElement ;
break ;
default :
node = node . ParentNode ;
break ;
}
}
}
return dictionary ;
}
public string LookupNamespace ( string prefix ) {
string namespaceName = nsManager . LookupNamespace ( prefix ) ;
if ( namespaceName = = null ) {
namespaceName = startNode . GetNamespaceOfPrefixStrict ( prefix ) ;
}
return namespaceName ;
}
public string LookupPrefix ( string namespaceName ) {
string prefix = nsManager . LookupPrefix ( namespaceName ) ;
if ( prefix = = null ) {
prefix = startNode . GetPrefixOfNamespaceStrict ( namespaceName ) ;
}
return prefix ;
}
private IXmlNamespaceResolver NamespaceResolver {
get {
if ( ( object ) startNode = = ( object ) document ) {
return nsManager ;
}
return this ;
}
}
private void CreateValidator ( XmlSchemaObject partialValidationType , XmlSchemaValidationFlags validationFlags ) {
validator = new XmlSchemaValidator ( nameTable , schemas , NamespaceResolver , validationFlags ) ;
validator . SourceUri = XmlConvert . ToUri ( document . BaseURI ) ;
validator . XmlResolver = null ;
validator . ValidationEventHandler + = internalEventHandler ;
validator . ValidationEventSender = this ;
if ( partialValidationType ! = null ) {
validator . Initialize ( partialValidationType ) ;
}
else {
validator . Initialize ( ) ;
}
}
private void ValidateNode ( XmlNode node ) {
currentNode = node ;
switch ( currentNode . NodeType ) {
case XmlNodeType . Document :
XmlElement docElem = ( ( XmlDocument ) node ) . DocumentElement ;
if ( docElem = = null ) {
throw new InvalidOperationException ( Res . GetString ( Res . Xml_InvalidXmlDocument , Res . GetString ( Res . Xdom_NoRootEle ) ) ) ;
}
ValidateNode ( docElem ) ;
break ;
case XmlNodeType . DocumentFragment :
case XmlNodeType . EntityReference :
for ( XmlNode child = node . FirstChild ; child ! = null ; child = child . NextSibling ) {
ValidateNode ( child ) ;
}
break ;
case XmlNodeType . Element :
ValidateElement ( ) ;
break ;
case XmlNodeType . Attribute : //Top-level attribute
XmlAttribute attr = currentNode as XmlAttribute ;
validator . ValidateAttribute ( attr . LocalName , attr . NamespaceURI , nodeValueGetter , attributeSchemaInfo ) ;
if ( psviAugmentation ) {
attr . XmlName = document . AddAttrXmlName ( attr . Prefix , attr . LocalName , attr . NamespaceURI , attributeSchemaInfo ) ;
}
break ;
case XmlNodeType . Text :
validator . ValidateText ( nodeValueGetter ) ;
break ;
case XmlNodeType . CDATA :
validator . ValidateText ( nodeValueGetter ) ;
break ;
case XmlNodeType . Whitespace :
case XmlNodeType . SignificantWhitespace :
validator . ValidateWhitespace ( nodeValueGetter ) ;
break ;
case XmlNodeType . Comment :
case XmlNodeType . ProcessingInstruction :
break ;
default :
throw new InvalidOperationException ( Res . GetString ( Res . Xml_UnexpectedNodeType , new string [ ] { currentNode . NodeType . ToString ( ) } ) ) ;
}
}
// SxS: This function calls ValidateElement on XmlSchemaValidator which is annotated with ResourceExposure attribute.
// Since the resource names passed to ValidateElement method are null and the function does not expose any resources
// it is fine to suppress the SxS warning.
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
[ResourceExposure(ResourceScope.None)]
private void ValidateElement ( ) {
nsManager . PushScope ( ) ;
XmlElement elementNode = currentNode as XmlElement ;
Debug . Assert ( elementNode ! = null ) ;
XmlAttributeCollection attributes = elementNode . Attributes ;
XmlAttribute attr = null ;
//Find Xsi attributes that need to be processed before validating the element
string xsiNil = null ;
string xsiType = null ;
for ( int i = 0 ; i < attributes . Count ; i + + ) {
attr = attributes [ i ] ;
string objectNs = attr . NamespaceURI ;
string objectName = attr . LocalName ;
Debug . Assert ( nameTable . Get ( attr . NamespaceURI ) ! = null ) ;
Debug . Assert ( nameTable . Get ( attr . LocalName ) ! = null ) ;
if ( Ref . Equal ( objectNs , NsXsi ) ) {
if ( Ref . Equal ( objectName , XsiType ) ) {
xsiType = attr . Value ;
}
else if ( Ref . Equal ( objectName , XsiNil ) ) {
xsiNil = attr . Value ;
}
}
else if ( Ref . Equal ( objectNs , NsXmlNs ) ) {
nsManager . AddNamespace ( attr . Prefix . Length = = 0 ? string . Empty : attr . LocalName , attr . Value ) ;
}
}
validator . ValidateElement ( elementNode . LocalName , elementNode . NamespaceURI , schemaInfo , xsiType , xsiNil , null , null ) ;
ValidateAttributes ( elementNode ) ;
validator . ValidateEndOfAttributes ( schemaInfo ) ;
//If element has children, drill down
for ( XmlNode child = elementNode . FirstChild ; child ! = null ; child = child . NextSibling ) {
ValidateNode ( child ) ;
}
//Validate end of element
currentNode = elementNode ; //Reset current Node for validation call back
validator . ValidateEndElement ( schemaInfo ) ;
//Get XmlName, as memberType / validity might be set now
if ( psviAugmentation ) {
elementNode . XmlName = document . AddXmlName ( elementNode . Prefix , elementNode . LocalName , elementNode . NamespaceURI , schemaInfo ) ;
if ( schemaInfo . IsDefault ) { //the element has a default value
XmlText textNode = document . CreateTextNode ( schemaInfo . SchemaElement . ElementDecl . DefaultValueRaw ) ;
elementNode . AppendChild ( textNode ) ;
}
}
nsManager . PopScope ( ) ; //Pop current namespace scope
}
private void ValidateAttributes ( XmlElement elementNode ) {
XmlAttributeCollection attributes = elementNode . Attributes ;
XmlAttribute attr = null ;
for ( int i = 0 ; i < attributes . Count ; i + + ) {
attr = attributes [ i ] ;
currentNode = attr ; //For nodeValueGetter to pick up the right attribute value
if ( Ref . Equal ( attr . NamespaceURI , NsXmlNs ) ) { //Do not validate namespace decls
continue ;
}
validator . ValidateAttribute ( attr . LocalName , attr . NamespaceURI , nodeValueGetter , attributeSchemaInfo ) ;
if ( psviAugmentation ) {
attr . XmlName = document . AddAttrXmlName ( attr . Prefix , attr . LocalName , attr . NamespaceURI , attributeSchemaInfo ) ;
}
}
if ( psviAugmentation ) {
//Add default attributes to the attributes collection
if ( defaultAttributes = = null ) {
defaultAttributes = new ArrayList ( ) ;
}
else {
defaultAttributes . Clear ( ) ;
}
validator . GetUnspecifiedDefaultAttributes ( defaultAttributes ) ;
XmlSchemaAttribute schemaAttribute = null ;
XmlQualifiedName attrQName ;
attr = null ;
for ( int i = 0 ; i < defaultAttributes . Count ; i + + ) {
schemaAttribute = defaultAttributes [ i ] as XmlSchemaAttribute ;
attrQName = schemaAttribute . QualifiedName ;
Debug . Assert ( schemaAttribute ! = null ) ;
attr = document . CreateDefaultAttribute ( GetDefaultPrefix ( attrQName . Namespace ) , attrQName . Name , attrQName . Namespace ) ;
SetDefaultAttributeSchemaInfo ( schemaAttribute ) ;
attr . XmlName = document . AddAttrXmlName ( attr . Prefix , attr . LocalName , attr . NamespaceURI , attributeSchemaInfo ) ;
attr . AppendChild ( document . CreateTextNode ( schemaAttribute . AttDef . DefaultValueRaw ) ) ;
attributes . Append ( attr ) ;
XmlUnspecifiedAttribute defAttr = attr as XmlUnspecifiedAttribute ;
if ( defAttr ! = null ) {
defAttr . SetSpecified ( false ) ;
}
}
}
}
private void SetDefaultAttributeSchemaInfo ( XmlSchemaAttribute schemaAttribute ) {
Debug . Assert ( attributeSchemaInfo ! = null ) ;
attributeSchemaInfo . Clear ( ) ;
attributeSchemaInfo . IsDefault = true ;
attributeSchemaInfo . IsNil = false ;
attributeSchemaInfo . SchemaType = schemaAttribute . AttributeSchemaType ;
attributeSchemaInfo . SchemaAttribute = schemaAttribute ;
//Get memberType for default attribute
SchemaAttDef attributeDef = schemaAttribute . AttDef ;
if ( attributeDef . Datatype . Variety = = XmlSchemaDatatypeVariety . Union ) {
XsdSimpleValue simpleValue = attributeDef . DefaultValueTyped as XsdSimpleValue ;
Debug . Assert ( simpleValue ! = null ) ;
attributeSchemaInfo . MemberType = simpleValue . XmlType ;
}
attributeSchemaInfo . Validity = XmlSchemaValidity . Valid ;
}
private string GetDefaultPrefix ( string attributeNS ) {
IDictionary < string , string > namespaceDecls = NamespaceResolver . GetNamespacesInScope ( XmlNamespaceScope . All ) ;
string defaultPrefix = null ;
string defaultNS ;
attributeNS = nameTable . Add ( attributeNS ) ; //atomize ns
foreach ( KeyValuePair < string , string > pair in namespaceDecls ) {
defaultNS = nameTable . Add ( pair . Value ) ;
if ( object . ReferenceEquals ( defaultNS , attributeNS ) ) {
defaultPrefix = pair . Key ;
if ( defaultPrefix . Length ! = 0 ) { //Locate first non-empty prefix
return defaultPrefix ;
}
}
}
return defaultPrefix ;
}
private object GetNodeValue ( ) {
return currentNode . Value ;
}
//Code for finding type during partial validation
private XmlSchemaObject FindSchemaInfo ( XmlElement elementToValidate ) {
isPartialTreeValid = true ;
Debug . Assert ( elementToValidate . ParentNode . NodeType ! = XmlNodeType . Document ) ; //Handle if it is the documentElement seperately
//Create nodelist to navigate down again
XmlNode currentNode = elementToValidate ;
IXmlSchemaInfo parentSchemaInfo = null ;
int nodeIndex = 0 ;
//Check common case of parent node first
XmlNode parentNode = currentNode . ParentNode ;
do {
parentSchemaInfo = parentNode . SchemaInfo ;
if ( parentSchemaInfo . SchemaElement ! = null | | parentSchemaInfo . SchemaType ! = null ) {
break ; //Found ancestor with schemaInfo
}
CheckNodeSequenceCapacity ( nodeIndex ) ;
nodeSequenceToValidate [ nodeIndex + + ] = parentNode ;
parentNode = parentNode . ParentNode ;
} while ( parentNode ! = null ) ;
if ( parentNode = = null ) { //Did not find any type info all the way to the root, currentNode is Document || DocumentFragment
nodeIndex = nodeIndex - 1 ; //Subtract the one for document and set the node to null
nodeSequenceToValidate [ nodeIndex ] = null ;
return GetTypeFromAncestors ( elementToValidate , null , nodeIndex ) ;
}
else {
//Start validating down from the parent or ancestor that has schema info and shallow validate all previous siblings
//to correctly ascertain particle for current node
CheckNodeSequenceCapacity ( nodeIndex ) ;
nodeSequenceToValidate [ nodeIndex + + ] = parentNode ;
XmlSchemaObject ancestorSchemaObject = parentSchemaInfo . SchemaElement ;
if ( ancestorSchemaObject = = null ) {
ancestorSchemaObject = parentSchemaInfo . SchemaType ;
}
return GetTypeFromAncestors ( elementToValidate , ancestorSchemaObject , nodeIndex ) ;
}
}
/ * private XmlSchemaElement GetTypeFromParent ( XmlElement elementToValidate , XmlSchemaComplexType parentSchemaType ) {
XmlQualifiedName elementName = new XmlQualifiedName ( elementToValidate . LocalName , elementToValidate . NamespaceURI ) ;
XmlSchemaElement elem = parentSchemaType . LocalElements [ elementName ] as XmlSchemaElement ;
if ( elem = = null ) { //Element not found as direct child of the content model. It might be invalid at this position or it might be a substitution member
SchemaInfo compiledSchemaInfo = schemas . CompiledInfo ;
XmlSchemaElement memberElem = compiledSchemaInfo . GetElement ( elementName ) ;
if ( memberElem ! = null ) {
}
}
} * /
private void CheckNodeSequenceCapacity ( int currentIndex ) {
if ( nodeSequenceToValidate = = null ) { //Normally users would call Validate one level down, this allows for 4
nodeSequenceToValidate = new XmlNode [ 4 ] ;
}
else if ( currentIndex > = nodeSequenceToValidate . Length - 1 ) { //reached capacity of array, Need to increase capacity to twice the initial
XmlNode [ ] newNodeSequence = new XmlNode [ nodeSequenceToValidate . Length * 2 ] ;
Array . Copy ( nodeSequenceToValidate , 0 , newNodeSequence , 0 , nodeSequenceToValidate . Length ) ;
nodeSequenceToValidate = newNodeSequence ;
}
}
private XmlSchemaAttribute FindSchemaInfo ( XmlAttribute attributeToValidate ) {
XmlElement parentElement = attributeToValidate . OwnerElement ;
XmlSchemaObject schemaObject = FindSchemaInfo ( parentElement ) ;
XmlSchemaComplexType elementSchemaType = GetComplexType ( schemaObject ) ;
if ( elementSchemaType = = null ) {
return null ;
}
XmlQualifiedName attName = new XmlQualifiedName ( attributeToValidate . LocalName , attributeToValidate . NamespaceURI ) ;
XmlSchemaAttribute schemaAttribute = elementSchemaType . AttributeUses [ attName ] as XmlSchemaAttribute ;
if ( schemaAttribute = = null ) {
XmlSchemaAnyAttribute anyAttribute = elementSchemaType . AttributeWildcard ;
if ( anyAttribute ! = null ) {
if ( anyAttribute . NamespaceList . Allows ( attName ) ) { //Match wildcard against global attribute
schemaAttribute = schemas . GlobalAttributes [ attName ] as XmlSchemaAttribute ;
}
}
}
return schemaAttribute ;
}
private XmlSchemaObject GetTypeFromAncestors ( XmlElement elementToValidate , XmlSchemaObject ancestorType , int ancestorsCount ) {
//schemaInfo is currentNode's schemaInfo
validator = CreateTypeFinderValidator ( ancestorType ) ;
schemaInfo = new XmlSchemaInfo ( ) ;
//start at the ancestor to start validating
int startIndex = ancestorsCount - 1 ;
bool ancestorHasWildCard = AncestorTypeHasWildcard ( ancestorType ) ;
for ( int i = startIndex ; i > = 0 ; i - - ) {
XmlNode node = nodeSequenceToValidate [ i ] ;
XmlElement currentElement = node as XmlElement ;
ValidateSingleElement ( currentElement , false , schemaInfo ) ;
if ( ! ancestorHasWildCard ) { //store type if ancestor does not have wildcard in its content model
currentElement . XmlName = document . AddXmlName ( currentElement . Prefix , currentElement . LocalName , currentElement . NamespaceURI , schemaInfo ) ;
//update wildcard flag
ancestorHasWildCard = AncestorTypeHasWildcard ( schemaInfo . SchemaElement ) ;
}
validator . ValidateEndOfAttributes ( null ) ;
if ( i > 0 ) {
ValidateChildrenTillNextAncestor ( node , nodeSequenceToValidate [ i - 1 ] ) ;
}
else { //i == 0
ValidateChildrenTillNextAncestor ( node , elementToValidate ) ;
}
}
Debug . Assert ( nodeSequenceToValidate [ 0 ] = = elementToValidate . ParentNode ) ;
//validate element whose type is needed,
ValidateSingleElement ( elementToValidate , false , schemaInfo ) ;
XmlSchemaObject schemaInfoFound = null ;
if ( schemaInfo . SchemaElement ! = null ) {
schemaInfoFound = schemaInfo . SchemaElement ;
}
else {
schemaInfoFound = schemaInfo . SchemaType ;
}
if ( schemaInfoFound = = null ) { //Detect if the node was validated lax or skip
if ( validator . CurrentProcessContents = = XmlSchemaContentProcessing . Skip ) {
if ( isPartialTreeValid ) { //Then node assessed as skip; if there was error we turn processContents to skip as well. But this is not the same as validating as skip.
return XmlSchemaComplexType . AnyTypeSkip ;
}
}
else if ( validator . CurrentProcessContents = = XmlSchemaContentProcessing . Lax ) {
return XmlSchemaComplexType . AnyType ;
}
}
return schemaInfoFound ;
}
private bool AncestorTypeHasWildcard ( XmlSchemaObject ancestorType ) {
XmlSchemaComplexType ancestorSchemaType = GetComplexType ( ancestorType ) ;
if ( ancestorType ! = null ) {
return ancestorSchemaType . HasWildCard ;
}
return false ;
}
private XmlSchemaComplexType GetComplexType ( XmlSchemaObject schemaObject ) {
if ( schemaObject = = null ) {
return null ;
}
XmlSchemaElement schemaElement = schemaObject as XmlSchemaElement ;
XmlSchemaComplexType complexType = null ;
if ( schemaElement ! = null ) {
complexType = schemaElement . ElementSchemaType as XmlSchemaComplexType ;
}
else {
complexType = schemaObject as XmlSchemaComplexType ;
}
return complexType ;
}
// SxS: This function calls ValidateElement on XmlSchemaValidator which is annotated with ResourceExposure attribute.
// Since the resource names passed to ValidateElement method are null and the function does not expose any resources
// it is fine to supress the warning.
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
[ResourceExposure(ResourceScope.None)]
private void ValidateSingleElement ( XmlElement elementNode , bool skipToEnd , XmlSchemaInfo newSchemaInfo ) {
nsManager . PushScope ( ) ;
Debug . Assert ( elementNode ! = null ) ;
XmlAttributeCollection attributes = elementNode . Attributes ;
XmlAttribute attr = null ;
//Find Xsi attributes that need to be processed before validating the element
string xsiNil = null ;
string xsiType = null ;
for ( int i = 0 ; i < attributes . Count ; i + + ) {
attr = attributes [ i ] ;
string objectNs = attr . NamespaceURI ;
string objectName = attr . LocalName ;
Debug . Assert ( nameTable . Get ( attr . NamespaceURI ) ! = null ) ;
Debug . Assert ( nameTable . Get ( attr . LocalName ) ! = null ) ;
if ( Ref . Equal ( objectNs , NsXsi ) ) {
if ( Ref . Equal ( objectName , XsiType ) ) {
xsiType = attr . Value ;
}
else if ( Ref . Equal ( objectName , XsiNil ) ) {
xsiNil = attr . Value ;
}
}
else if ( Ref . Equal ( objectNs , NsXmlNs ) ) {
nsManager . AddNamespace ( attr . Prefix . Length = = 0 ? string . Empty : attr . LocalName , attr . Value ) ;
}
}
validator . ValidateElement ( elementNode . LocalName , elementNode . NamespaceURI , newSchemaInfo , xsiType , xsiNil , null , null ) ;
//Validate end of element
if ( skipToEnd ) {
validator . ValidateEndOfAttributes ( newSchemaInfo ) ;
validator . SkipToEndElement ( newSchemaInfo ) ;
nsManager . PopScope ( ) ; //Pop current namespace scope
}
}
private void ValidateChildrenTillNextAncestor ( XmlNode parentNode , XmlNode childToStopAt ) {
XmlNode child ;
for ( child = parentNode . FirstChild ; child ! = null ; child = child . NextSibling ) {
if ( child = = childToStopAt ) {
break ;
}
switch ( child . NodeType ) {
case XmlNodeType . EntityReference :
ValidateChildrenTillNextAncestor ( child , childToStopAt ) ;
break ;
case XmlNodeType . Element : //Flat validation, do not drill down into children
ValidateSingleElement ( child as XmlElement , true , null ) ;
break ;
case XmlNodeType . Text :
case XmlNodeType . CDATA :
validator . ValidateText ( child . Value ) ;
break ;
case XmlNodeType . Whitespace :
case XmlNodeType . SignificantWhitespace :
validator . ValidateWhitespace ( child . Value ) ;
break ;
case XmlNodeType . Comment :
case XmlNodeType . ProcessingInstruction :
break ;
default :
throw new InvalidOperationException ( Res . GetString ( Res . Xml_UnexpectedNodeType , new string [ ] { currentNode . NodeType . ToString ( ) } ) ) ;
}
}
Debug . Assert ( child = = childToStopAt ) ;
}
private XmlSchemaValidator CreateTypeFinderValidator ( XmlSchemaObject partialValidationType ) {
XmlSchemaValidator findTypeValidator = new XmlSchemaValidator ( document . NameTable , document . Schemas , this . nsManager , XmlSchemaValidationFlags . None ) ;
findTypeValidator . ValidationEventHandler + = new ValidationEventHandler ( TypeFinderCallBack ) ;
if ( partialValidationType ! = null ) {
findTypeValidator . Initialize ( partialValidationType ) ;
}
else { //If we walked up to the root and no schemaInfo was there, start validating from root
findTypeValidator . Initialize ( ) ;
}
return findTypeValidator ;
}
private void TypeFinderCallBack ( object sender , ValidationEventArgs arg ) {
if ( arg . Severity = = XmlSeverityType . Error ) {
isPartialTreeValid = false ;
}
}
private void InternalValidationCallBack ( object sender , ValidationEventArgs arg ) {
if ( arg . Severity = = XmlSeverityType . Error ) {
isValid = false ;
}
XmlSchemaValidationException ex = arg . Exception as XmlSchemaValidationException ;
Debug . Assert ( ex ! = null ) ;
ex . SetSourceObject ( currentNode ) ;
if ( this . eventHandler ! = null ) { //Invoke user's event handler
eventHandler ( sender , arg ) ;
}
else if ( arg . Severity = = XmlSeverityType . Error ) {
throw ex ;
}
}
}
}