Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Design / system / Data / Services / Design / Xml / XNodeSchemaApplier.cs / 1305376 / XNodeSchemaApplier.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// Provides a class used to make an XElement conform to a given // XML Schema. // // // @owner [....] //--------------------------------------------------------------------- namespace System.Data.Services.Design.Xml { #region Namespaces. using System.Diagnostics; using System; using System.Linq; using System.Xml; using System.Xml.Schema; using System.Xml.Linq; using System.Collections.Generic; using System.Runtime.Versioning; #endregion Namespaces. ///Use this class to remove unexpected elements and attributes from an XDocument instance. internal class XNodeSchemaApplier { #region Private fields. ///Namespace manager for current scope. private readonly XmlNamespaceManager namespaceManager; ///Schemas used to predict expected elements and attributes. private readonly XmlSchemaSet schemas; ///XName for xsi:type. private readonly XName xsiTypeName; ///XName for xsi:nil. private readonly XName xsiNilName; ///Schema validator used to predict expected elements and attributes. private XmlSchemaValidator validator; #endregion Private fields. #region Constructors. ///Initializes a new /// Schemas to use to predict elements and attributes. private XNodeSchemaApplier(XmlSchemaSet schemas) { Debug.Assert(schemas != null, "schemas != null"); this.schemas = schemas; XNamespace xsi = XNamespace.Get("http://www.w3.org/2001/XMLSchema-instance"); this.xsiTypeName = xsi.GetName("type"); this.xsiNilName = xsi.GetName("nil"); this.namespaceManager = new XmlNamespaceManager(schemas.NameTable); } #endregion Constructors. #region Internal methods. ///instance. /// Appends ///to the specified , creating as necessary. /// List element type. /// List to add the element to, possibly null on entry. /// Element to add to the list. internal static void AppendWithCreation(ref List list, T element) { if (list == null) { list = new List (); } list.Add(element); } /// /// Applies the specified /// Set of schemas to apply. /// Document to remove elements and attributes from. internal static void Apply(XmlSchemaSet schemas, XElement element) { Debug.Assert(schemas != null, "schemas != null"); Debug.Assert(element != null, "document != null"); XNodeSchemaApplier applier = new XNodeSchemaApplier(schemas); applier.Validate(element); } #endregion Internal methods. #region Private methods. ///to remove unexpected elements and attributes from the /// given . /// Determines whether the specified /// Element to check. /// ///is expected. of the (passed to avoid recreation). /// /// Expected schema particle. /// true if the element is expected; false otherwise. private static bool IsElementExpected(XElement element, XmlQualifiedName elementName, XmlSchemaParticle expected) { Debug.Assert(element != null, "element != null"); Debug.Assert(elementName != null, "elementName != null"); Debug.Assert(expected != null, "expected != null"); Debug.Assert( ToQualifiedName(element.Name) == elementName, "ToQualifiedName(element.Name) == elementName -- otherwise the caller get the 'caching' wrong"); // These are all possibilities for a particle. XmlSchemaGroupRef schemaGroupRef = expected as XmlSchemaGroupRef; XmlSchemaAny schemaAny = expected as XmlSchemaAny; XmlSchemaElement schemaElement = expected as XmlSchemaElement; XmlSchemaAll schemaAll = expected as XmlSchemaAll; XmlSchemaChoice schemaChoice = expected as XmlSchemaChoice; XmlSchemaSequence schemaSequence = expected as XmlSchemaSequence; Debug.Assert(schemaGroupRef == null, "schemaGroupRef == null -- the validator flattens this out as options."); Debug.Assert(schemaSequence == null, "schemaSequence == null -- the validator flattens this out and picks the right one in seq."); Debug.Assert(schemaAll == null, "schemaAll == null -- the validator flattens this out as options."); Debug.Assert(schemaChoice == null, "schemaChoice == null -- the validator flattens this out as options."); if (schemaAny != null) { Debug.Assert( schemaAny.Namespace == "##other" || schemaAny.Namespace == "##any", "schemaAny.Namespace == '##other' || '##any' -- otherwise CSDL XSD resource was changed"); if (schemaAny.Namespace == "##any") { return true; } else if (schemaAny.Namespace == "##other") { string realElementNamespace = element.Name.NamespaceName; if (realElementNamespace != GetTargetNamespace(expected)) { return true; } } } if (schemaElement != null) { if (schemaElement.QualifiedName == elementName) { return true; } } return false; } ///Gets the target namespace that applies to the specified /// XML schema object for which to get target namespace. ///. Target namespace for the specified private static string GetTargetNamespace(XmlSchemaObject schemaObject) { Debug.Assert(schemaObject != null, "schemaObject != null"); string result = null; do { XmlSchema schema = schemaObject as XmlSchema; if (schema != null) { result = schema.TargetNamespace; Debug.Assert(!String.IsNullOrEmpty(schema.TargetNamespace), "schema.TargetNamespace != null||'' -- otherwise this isn't CSDL"); } else { schemaObject = schemaObject.Parent; Debug.Assert(schemaObject != null, "o != null -- otherwise the object isn't parented to a schema"); } } while (result == null); return result; } ///(never null). Determines whether the specified /// Element to check. /// Expected schema particles (possibly empty). ///is expected. true if the element is expected; false otherwise. private static bool IsElementExpected(XElement element, XmlSchemaParticle[] expectedParticles) { Debug.Assert(element != null, "element != null"); Debug.Assert(expectedParticles != null, "expectedParticles != null"); XmlQualifiedName elementName = ToQualifiedName(element.Name); foreach (var expected in expectedParticles) { if (IsElementExpected(element, elementName, expected)) { return true; } } return false; } ///Determines whether the specified /// Attribute to check. /// Expected attributes (possibly empty). /// anyAttribute schema for a complex type element (possibly null). ///is expected. true if the attribute is expected; false otherwise. private static bool IsAttributeExpected(XAttribute attribute, XmlSchemaAnyAttribute anyAttribute, XmlSchemaAttribute[] expectedAttributes) { Debug.Assert(attribute != null, "attribute != null"); Debug.Assert(expectedAttributes != null, "expectedAttributes != null"); Debug.Assert(expectedAttributes.All(a => a.Form != XmlSchemaForm.Qualified), "expectedAttributes.All(a => a.Form != XmlSchemaForm.Qualified)"); var name = ToQualifiedName(attribute.Name); if (name.Namespace.Length == 0) { foreach (var expected in expectedAttributes) { if (expected.Name == name.Name) { return true; } } } if (anyAttribute != null) { Debug.Assert( anyAttribute.Namespace == "##any" || anyAttribute.Namespace == "##other", "anyAttribute.Namespace == '##any' || '##other' -- otherwise CSDL XSD resource was changed"); if (anyAttribute.Namespace == "##any") { return true; } else { string attributeNamespace = attribute.Name.NamespaceName; if (attributeNamespace.Length > 0 && attributeNamespace != GetTargetNamespace(anyAttribute)) { return true; } } } return false; } ////// Return the /// XML name to return. ///representation of the specified . /// An private static XmlQualifiedName ToQualifiedName(XName name) { Debug.Assert(name != null, "name != null"); return new XmlQualifiedName(name.LocalName, name.NamespaceName); } ///that represents the given . Validates the specified /// Source object for validation (must be an element). private void Validate(XElement element) { Debug.Assert(element != null, "element != null"); XmlSchemaValidationFlags validationFlags = XmlSchemaValidationFlags.AllowXmlAttributes; this.PushAncestorsAndSelf(element.Parent); validator = new XmlSchemaValidator(schemas.NameTable, schemas, namespaceManager, validationFlags); validator.XmlResolver = null; validator.Initialize(); this.ValidateElement(element); validator.EndValidation(); } ///object. Pushes the specifed /// Element to push from - possibly null. ///namespaces and those of ancestors. /// Pushing in reverse order (up the tree rather than down the tree) is OK, because we check that /// the namespace local name hasn't been added yet. Use private void PushAncestorsAndSelf(XElement element) { while (element != null) { foreach (XAttribute attribute in element.Attributes()) { if (attribute.IsNamespaceDeclaration) { string localName = attribute.Name.LocalName; if (localName == "xmlns") { localName = string.Empty; } if (!namespaceManager.HasNamespace(localName)) { namespaceManager.AddNamespace(localName, attribute.Value); } } } element = element.Parent as XElement; } } ///as we go down /// the tree to push/pop as usual. /// Pushes the specifed /// Element to push. /// The value for xsi:type on this element. /// The value for xsi:nil on this element. private void PushElement(XElement element, ref string xsiType, ref string xsiNil) { Debug.Assert(element != null, "e != null"); namespaceManager.PushScope(); foreach (XAttribute attribute in element.Attributes()) { if (attribute.IsNamespaceDeclaration) { string localName = attribute.Name.LocalName; if (localName == "xmlns") { localName = string.Empty; } namespaceManager.AddNamespace(localName, attribute.Value); } else { XName name = attribute.Name; if (name == xsiTypeName) { xsiType = attribute.Value; } else if (name == xsiNilName) { xsiNil = attribute.Value; } } } } ///namespaces and those of ancestors. Validates all attributes on the specified /// Element to validate attributes on. private void ValidateAttributes(XElement element) { Debug.Assert(element != null, "e != null"); foreach (XAttribute attribute in element.Attributes()) { if (!attribute.IsNamespaceDeclaration) { validator.ValidateAttribute(attribute.Name.LocalName, attribute.Name.NamespaceName, attribute.Value, null); } } } //// SxS: This method does not expose any resources to the caller and passes null as resource names to //// XmlSchemaValidator.ValidateElement (annotated with ResourceExposure(ResourceScope.None). //// It's OK to suppress the SxS warning. [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] [ResourceExposure(ResourceScope.None)] private void ValidateElement(XElement e) { Debug.Assert(e != null, "e != null"); XmlSchemaInfo schemaInfo = new XmlSchemaInfo(); string xsiType = null; string xsiNil = null; this.PushElement(e, ref xsiType, ref xsiNil); // The current element is always valid - otherwise we wouldn't have recursed into it in the first place. validator.ValidateElement(e.Name.LocalName, e.Name.NamespaceName, schemaInfo, xsiType, xsiNil, null, null); // When we have no schema element, then e was included but we don't know about it - it's an extension // element, likely under CSDL documentation. We'll skip the whole thing in this case. if (schemaInfo.SchemaElement != null) { XmlSchemaComplexType schemaComplexType = schemaInfo.SchemaElement.ElementSchemaType as XmlSchemaComplexType; this.TrimAttributes(e, (schemaComplexType == null) ? null : schemaComplexType.AttributeWildcard); this.ValidateAttributes(e); validator.ValidateEndOfAttributes(null); this.TrimAndValidateNodes(e); } validator.ValidateEndElement(null); this.namespaceManager.PopScope(); } ///. Removes attributes from the specified /// Element to remove attributes from. /// anyAttribute schema for a complex type element (possibly null). private void TrimAttributes(XElement element, XmlSchemaAnyAttribute anyAttribute) { Debug.Assert(element != null, "e != null"); Listif they're unexpected. unexpectedAttributes = null; var expectedAttributes = validator.GetExpectedAttributes(); foreach (XAttribute attribute in element.Attributes()) { if (attribute.IsNamespaceDeclaration) { continue; } if (!IsAttributeExpected(attribute, anyAttribute, expectedAttributes)) { AppendWithCreation(ref unexpectedAttributes, attribute); } } if (unexpectedAttributes != null) { foreach (var attribute in unexpectedAttributes) { attribute.Remove(); } } } /// /// Removes nodes from the specified /// ///element and validates its nodes. /// /// While it's cleaner to do this in two passes, trim then validate, like we do with attributes, we need to /// validate as we go for the validator to return sequence elements in the right order. /// private void TrimAndValidateNodes(XElement parent) { Debug.Assert(parent != null, "parent != null"); ListunexpectedNodes = null; XmlSchemaParticle[] expectedParticles = null; foreach (XNode node in parent.Nodes()) { // expectedParticles will be null the first iteration and right after we validate, // when we potentially have something different to validate against. if (expectedParticles == null) { expectedParticles = validator.GetExpectedParticles(); } Debug.Assert(expectedParticles != null, "expectedParticles != null -- GetExpectedParticles should return empty at worst"); XElement element = node as XElement; if (element != null) { if (!IsElementExpected(element, expectedParticles)) { AppendWithCreation(ref unexpectedNodes, element); } else { this.ValidateElement(element); expectedParticles = null; } } else { XText text = node as XText; if (text != null) { string s = text.Value; if (s.Length > 0) { validator.ValidateText(s); expectedParticles = null; } } } } if (unexpectedNodes != null) { foreach (var node in unexpectedNodes) { node.Remove(); } } } #endregion Private methods. } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Attributes.cs
- XmlCollation.cs
- RightsManagementEncryptedStream.cs
- SoapIncludeAttribute.cs
- CodeDirectionExpression.cs
- unsafenativemethodstextservices.cs
- coordinatorfactory.cs
- DesignRelationCollection.cs
- CmsInterop.cs
- DropShadowEffect.cs
- TypeSystemProvider.cs
- CfgSemanticTag.cs
- FrugalList.cs
- TypeInitializationException.cs
- ChangeProcessor.cs
- Component.cs
- BitmapEffectDrawingContextState.cs
- unsafenativemethodsother.cs
- CodeTypeReference.cs
- Utility.cs
- BreakRecordTable.cs
- ConfigurationValue.cs
- BrowsableAttribute.cs
- ISAPIApplicationHost.cs
- TemplatedMailWebEventProvider.cs
- ActivationServices.cs
- _Rfc2616CacheValidators.cs
- DrawingBrush.cs
- VerificationAttribute.cs
- GregorianCalendarHelper.cs
- Activator.cs
- FaultReason.cs
- Validator.cs
- HttpModuleAction.cs
- BackgroundFormatInfo.cs
- BoundingRectTracker.cs
- ZipFileInfoCollection.cs
- InProcStateClientManager.cs
- ObsoleteAttribute.cs
- KnownTypesProvider.cs
- UserControlBuildProvider.cs
- MobileComponentEditorPage.cs
- WebPartVerbCollection.cs
- IPAddress.cs
- Animatable.cs
- ClientType.cs
- RegexBoyerMoore.cs
- WebPartUserCapability.cs
- bidPrivateBase.cs
- DataGridColumn.cs
- KeyValuePairs.cs
- SafeEventLogReadHandle.cs
- Int32Animation.cs
- ThicknessAnimationUsingKeyFrames.cs
- CreateUserWizardAutoFormat.cs
- HostingEnvironment.cs
- DrawingCollection.cs
- TextDecoration.cs
- CodeTypeOfExpression.cs
- Menu.cs
- QueryExpr.cs
- ObjectQueryState.cs
- regiisutil.cs
- ThaiBuddhistCalendar.cs
- Attributes.cs
- StaticSiteMapProvider.cs
- MenuAdapter.cs
- NextPreviousPagerField.cs
- ReflectionTypeLoadException.cs
- ContainerUtilities.cs
- _UriTypeConverter.cs
- ContextQuery.cs
- CustomAttributeBuilder.cs
- wgx_commands.cs
- NumericUpDown.cs
- DefaultBindingPropertyAttribute.cs
- LambdaCompiler.Logical.cs
- ObjectDataSourceStatusEventArgs.cs
- NotifyCollectionChangedEventArgs.cs
- MethodInfo.cs
- PriorityBindingExpression.cs
- XmlDocumentSchema.cs
- TypedElement.cs
- DataContractSerializerOperationBehavior.cs
- NotifyParentPropertyAttribute.cs
- ViewStateModeByIdAttribute.cs
- StyleBamlRecordReader.cs
- SystemResourceKey.cs
- TimeSpanValidatorAttribute.cs
- GlyphRunDrawing.cs
- DataGridTable.cs
- SoapRpcMethodAttribute.cs
- DesignerGeometryHelper.cs
- PropertyChangedEventArgs.cs
- ParallelActivityDesigner.cs
- StateMachineHelpers.cs
- SqlRowUpdatingEvent.cs
- ConstraintManager.cs
- ExponentialEase.cs
- CopyAttributesAction.cs