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
- ExpandedProjectionNode.cs
- NativeMethods.cs
- EventProvider.cs
- DataServiceRequestOfT.cs
- QilChoice.cs
- AutomationFocusChangedEventArgs.cs
- BitmapMetadataEnumerator.cs
- TraceContext.cs
- SiteMapNodeItemEventArgs.cs
- DesignerView.Commands.cs
- ItemDragEvent.cs
- Evaluator.cs
- ScalarRestriction.cs
- DataRowCollection.cs
- ArgumentReference.cs
- OutputCacheSection.cs
- DataListItem.cs
- EncryptedReference.cs
- AddValidationError.cs
- Material.cs
- PointAnimationUsingPath.cs
- EventSetter.cs
- LabelAutomationPeer.cs
- GeneralTransform2DTo3DTo2D.cs
- ClientBuildManagerCallback.cs
- GroupItemAutomationPeer.cs
- PageStatePersister.cs
- OwnerDrawPropertyBag.cs
- DataGridColumnStyleMappingNameEditor.cs
- CorrelationToken.cs
- SingleTagSectionHandler.cs
- ExceptionHandler.cs
- ExtendedProperty.cs
- SqlPersonalizationProvider.cs
- DataGrid.cs
- MatrixTransform3D.cs
- Grammar.cs
- basemetadatamappingvisitor.cs
- WebPartConnectionsDisconnectVerb.cs
- DefaultTextStore.cs
- CodeTypeDeclarationCollection.cs
- MenuRendererClassic.cs
- MouseEventArgs.cs
- EncryptedPackageFilter.cs
- TraceUtility.cs
- SchemaMerger.cs
- OdbcCommandBuilder.cs
- DataListItemEventArgs.cs
- RelationshipNavigation.cs
- COM2Properties.cs
- XamlStyleSerializer.cs
- WebPartMenuStyle.cs
- GridSplitter.cs
- DebugView.cs
- SQLConvert.cs
- StringSource.cs
- ChannelSinkStacks.cs
- MailSettingsSection.cs
- WebConfigurationHostFileChange.cs
- BindingsCollection.cs
- Label.cs
- IdentifierCreationService.cs
- DataBoundControlDesigner.cs
- UInt32.cs
- XmlILStorageConverter.cs
- AtomServiceDocumentSerializer.cs
- CodeNamespaceCollection.cs
- InputManager.cs
- ToggleProviderWrapper.cs
- LocalizableResourceBuilder.cs
- BaseTemplatedMobileComponentEditor.cs
- Positioning.cs
- TextTreeNode.cs
- WindowsSecurityToken.cs
- _HelperAsyncResults.cs
- CommunicationObjectAbortedException.cs
- MessageSecurityOverMsmq.cs
- OletxDependentTransaction.cs
- DurationConverter.cs
- EditorBrowsableAttribute.cs
- StylusPoint.cs
- GeneralTransform3D.cs
- AsyncStreamReader.cs
- Listbox.cs
- FilterEventArgs.cs
- SqlEnums.cs
- ManipulationLogic.cs
- Int32Converter.cs
- DirtyTextRange.cs
- DataSvcMapFile.cs
- EntityCodeGenerator.cs
- PhysicalFontFamily.cs
- QuaternionAnimation.cs
- WebPartUserCapability.cs
- XmlArrayAttribute.cs
- FontFaceLayoutInfo.cs
- CrossSiteScriptingValidation.cs
- DesignSurface.cs
- BindingList.cs
- RequestReplyCorrelator.cs