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
- ButtonField.cs
- Util.cs
- ByteConverter.cs
- ComponentResourceKeyConverter.cs
- itemelement.cs
- XmlUrlResolver.cs
- TypefaceMetricsCache.cs
- XmlAggregates.cs
- ProcessModuleCollection.cs
- FormsAuthenticationCredentials.cs
- UrlMapping.cs
- FontStyles.cs
- UniqueTransportManagerRegistration.cs
- InvalidPrinterException.cs
- MsmqReceiveParameters.cs
- ParallelEnumerable.cs
- ApplicationContext.cs
- TransformerTypeCollection.cs
- OperationFormatter.cs
- Rect3D.cs
- XmlDsigSep2000.cs
- TransformedBitmap.cs
- initElementDictionary.cs
- Int32RectConverter.cs
- RectKeyFrameCollection.cs
- OdbcCommandBuilder.cs
- AuthenticationManager.cs
- TrackBarDesigner.cs
- TextTreeNode.cs
- EntityDataSourceWizardForm.cs
- SQLRoleProvider.cs
- ListViewItemMouseHoverEvent.cs
- ArrayElementGridEntry.cs
- DispatcherFrame.cs
- SoapSchemaImporter.cs
- SessionEndingEventArgs.cs
- NativeMethods.cs
- DragDeltaEventArgs.cs
- SqlParameterCollection.cs
- StartUpEventArgs.cs
- CodeIdentifiers.cs
- Binding.cs
- NegotiateStream.cs
- InternalBufferOverflowException.cs
- ByteAnimationUsingKeyFrames.cs
- XmlLinkedNode.cs
- TraceHandlerErrorFormatter.cs
- AppDomainFactory.cs
- CredentialCache.cs
- SqlRemoveConstantOrderBy.cs
- SiteMapNodeItemEventArgs.cs
- Wrapper.cs
- TaskResultSetter.cs
- OleStrCAMarshaler.cs
- Atom10FormatterFactory.cs
- NavigationEventArgs.cs
- OracleNumber.cs
- FtpRequestCacheValidator.cs
- System.Data_BID.cs
- NavigationHelper.cs
- TreeNodeCollection.cs
- HttpConfigurationSystem.cs
- ByeOperationAsyncResult.cs
- StaticFileHandler.cs
- DataGridPageChangedEventArgs.cs
- StreamSecurityUpgradeAcceptorAsyncResult.cs
- CodeNamespaceImportCollection.cs
- TextSpanModifier.cs
- DiscoveryVersionConverter.cs
- XmlSchemaObjectCollection.cs
- Enlistment.cs
- Exceptions.cs
- MailAddressCollection.cs
- ZipIOLocalFileDataDescriptor.cs
- IdnMapping.cs
- SiteMapDataSourceView.cs
- FixedPageStructure.cs
- UIElementCollection.cs
- filewebresponse.cs
- errorpatternmatcher.cs
- ProxyDataContractResolver.cs
- TimeoutValidationAttribute.cs
- TraceHwndHost.cs
- MetadataCacheItem.cs
- SchemaEntity.cs
- EditorZoneBase.cs
- TextTabProperties.cs
- SoapObjectReader.cs
- initElementDictionary.cs
- SafeHandles.cs
- HostingEnvironmentSection.cs
- MembershipUser.cs
- _ListenerRequestStream.cs
- BaseContextMenu.cs
- FieldBuilder.cs
- HtmlInputCheckBox.cs
- DetailsViewRow.cs
- TypedTableBase.cs
- EntityParameterCollection.cs
- ObjectDataSourceEventArgs.cs