private static IEnumerable <IAdapterCreator> GetAdapterCreators(DomNode node, Type type) { DomNodeType nodeType = node.Type; if (nodeType.m_adapterCreatorCache == null) { nodeType.m_adapterCreatorCache = new Dictionary <Type, IEnumerable <IAdapterCreator> >(); } IEnumerable <IAdapterCreator> adapterCreators; if (!nodeType.m_adapterCreatorCache.TryGetValue(type, out adapterCreators)) { // build an array of adapter creators that can adapt the node List <IAdapterCreator> creators = new List <IAdapterCreator>(); while (nodeType != null) { if (nodeType.m_adapterCreators != null) { foreach (IAdapterCreator creator in nodeType.m_adapterCreators) { if (creator.CanAdapt(node, type)) { creators.Add(creator); } } } nodeType = nodeType.BaseType; } // for empty arrays, use global instance adapterCreators = (creators.Count > 0) ? creators.ToArray() : EmptyEnumerable <IAdapterCreator> .Instance; // cache the result for subsequent searches node.Type.m_adapterCreatorCache.Add(type, adapterCreators); } return(adapterCreators); }
// try to obtain enumeration values from xml annotations // Legacy ATF 2.8 example: // <xs:simpleType name="EmotionType"> // <xs:annotation> // <xs:appinfo> // <scea.dom.editors.enumeration name="Adequate" displayName="Adequate, good enough"/> // <scea.dom.editors.enumeration name="Capable" displayName="Capable, you betcha!"/> // <scea.dom.editors.enumeration name="Enthusiastic" /> // </xs:appinfo> // </xs:annotation> // <xs:restriction base="xs:string"> // <xs:enumeration value="Adequate"/> // <xs:enumeration value="Capable"/> // <xs:enumeration value="Enthusiastic"/> // </xs:restriction> // </xs:simpleType> private static string[] TryGetEnumeration(DomNodeType domNodeType, XmlNode annotation) { string[] enumeration = null; XmlAttribute targetDomAttribute = annotation.Attributes[AnnotationsNameAttribute]; if (targetDomAttribute != null) { var domObjectAttribute = domNodeType.GetAttributeInfo(targetDomAttribute.Value); if (domObjectAttribute != null) { var attributeType = domObjectAttribute.Type; var xmlAnnotation = attributeType.GetTag <IEnumerable <XmlNode> >(); if (xmlAnnotation != null) { List <string> enumerationList = new List <string>(); foreach (XmlNode enumAnnotation in xmlAnnotation) { if (enumAnnotation.Name == AnnotationsLegacyEnumeration) { string name = enumAnnotation.Attributes[AnnotationsNameAttribute].Value; XmlNode displayNode = enumAnnotation.Attributes.GetNamedItem(AnnotationsDisplayNameAttribute); if (displayNode != null) { enumerationList.Add(name + "==" + displayNode.Value); } else { enumerationList.Add(name); } } enumeration = enumerationList.ToArray(); } } } } return(enumeration); }
/// <summary> /// Checks all property descriptors of adapter type and when an ObservableDomPropertyAttribute /// is present on the descriptor, finds the AttributeInfo with matching name on the DomNodeType, /// and sets PropertyChangedEventArgs tags to match</summary> /// <param name="adapterType">Type of adapter</param> /// <param name="nodeType">DomNode type</param> private static void AddAttributeTags(Type adapterType, DomNodeType nodeType) { foreach (var property in adapterType.GetProperties()) { object[] attributes = property.GetCustomAttributes(typeof(ObservableDomPropertyAttribute), true); if (attributes != null && attributes.Length > 0) { var eventArgs = new PropertyChangedEventArgs(property.Name); foreach (var attribute in attributes) { var attributeName = ((ObservableDomPropertyAttribute)attribute).AttributeName; var currentType = nodeType; var attributeInfo = currentType.GetAttributeInfo(attributeName); Requires.NotNull(attributeInfo, "Unrecognized attribute name in ObservableDomPropertyAttribute"); // Each base type may have duplicate attributeInfo if it is an inherited attribute // We need to set the tag on each base attributeInfo so that the PropertyChanged event // will be raised even if the attribute is set on a base type while (currentType != DomNodeType.BaseOfAllTypes && attributeInfo != null) { var args = attributeInfo.GetTagLocal <PropertyChangedEventArgsCollection>(); if (args == null) { args = new PropertyChangedEventArgsCollection(); attributeInfo.SetTag(args); } args.Add(eventArgs); currentType = currentType.BaseType; attributeInfo = currentType.GetAttributeInfo(attributeName); } } } } }
/// <summary> /// Constructor</summary> /// <param name="name">Name of node type</param> /// <param name="baseType">Base node type. 'null' equates to DomNodeType.BaseOfAllTypes</param> /// <param name="attributes">Attributes for node type, or null</param> /// <param name="children">Children for node type, or null</param> /// <param name="extensions">Extensions for node type, or null</param> public DomNodeType( string name, DomNodeType baseType, IEnumerable <AttributeInfo> attributes, IEnumerable <ChildInfo> children, IEnumerable <ExtensionInfo> extensions) : base(name) { SetBaseType(baseType); if (attributes != null) { m_definitions.Attributes.AddRange(attributes); } if (children != null) { m_definitions.Children.AddRange(children); } if (extensions != null) { m_definitions.Extensions.AddRange(extensions); } }
/// <summary> /// Constructor</summary> /// <param name="name">Name of node type</param> /// <param name="baseType">Base node type. 'null' equates to DomNodeType.BaseOfAllTypes</param> /// <param name="metadata">Zero or more AttributeInfo, ChildInfo, or ExtensionInfo objects</param> public DomNodeType( string name, DomNodeType baseType, params FieldMetadata[] metadata) : base(name) { SetBaseType(baseType); foreach (FieldMetadata info in metadata) { if (info is AttributeInfo) { m_definitions.Attributes.Add((AttributeInfo)info); } else if (info is ChildInfo) { m_definitions.Children.Add((ChildInfo)info); } else if (info is ExtensionInfo) { m_definitions.Extensions.Add((ExtensionInfo)info); } } }
/// <summary> /// Gets the descendant metadata corresponding to the given path</summary> /// <param name="path">Path to descendant, with ':' as separator</param> /// <returns>Descendant metadata corresponding to the given path</returns> public ChildInfo GetDescendantInfo(string path) { if (path == null) { throw new ArgumentNullException("path"); } ChildInfo result = null; DomNodeType type = this; string[] segments = path.Split(':'); foreach (string segment in segments) { result = type.GetChildInfo(segment); if (result == null) { break; } type = result.Type; } return(result); }
/// <summary> /// Adds a node type to the ones defined by the schema</summary> /// <remarks>If the node type is already defined, it is overwritten</remarks> /// <param name="name">Name of node type</param> /// <param name="type">New node type</param> public void AddNodeType(string name, DomNodeType type) { m_nodeTypeCollection.AddNodeType(name, type); }
/// <summary> /// Gets all node types derived from base type</summary> /// <param name="baseType">Base type</param> /// <remarks>Base type is not returned in the array.</remarks> /// <returns>Enumeration of all node types derived from baseType</returns> public IEnumerable <DomNodeType> GetNodeTypes(DomNodeType baseType) { return(m_nodeTypeCollection.GetNodeTypes(baseType)); }
private static PropertyDescriptor GetDescriptor( DomNodeType type, XmlNode annotation, string name, string[] segments) { PropertyDescriptor desc = null; // Get mandatory display name XmlAttribute displayNameAttr = annotation.Attributes["displayName"]; if (displayNameAttr != null) { if (string.IsNullOrEmpty(name)) { throw new AnnotationException(string.Format( "Required name attribute is null or empty.\r\nType: {0}\r\nElement: {1}", type.Name, annotation.Name)); } string displayName = displayNameAttr.Value; if (string.IsNullOrEmpty(displayName)) { displayName = name; } // Get optional annotations string category = GetAnnotation(annotation, "category"); string description = GetAnnotation(annotation, "description"); bool readOnly = GetAnnotation(annotation, "readOnly") == "true"; object editor = CreateObject <object>(type, annotation, "editor"); TypeConverter typeConverter = CreateObject <TypeConverter>(type, annotation, "converter"); if (annotation.Name == "scea.dom.editors.attribute") { // Attribute annotation if (segments == null) { throw new AnnotationException("Unnamed attribute"); } if (segments.Length == 1) // local attribute { AttributeInfo metaAttr = type.GetAttributeInfo(name); if (metaAttr == null) { throw new AnnotationException("Type doesn't have this attribute"); } desc = new AttributePropertyDescriptor( displayName, metaAttr, category, description, readOnly, editor, typeConverter); } else // descendant attribute { ChildInfo[] metaElements = GetPath(type, segments, segments.Length - 1); DomNodeType childType = metaElements[segments.Length - 2].Type; AttributeInfo metaAttr = childType.GetAttributeInfo(segments[segments.Length - 1]); if (metaAttr == null) { throw new AnnotationException("Descendant type doesn't have this attribute"); } desc = new ChildAttributePropertyDescriptor( displayName, metaAttr, metaElements, category, description, readOnly, editor, typeConverter); } } else if (annotation.Name == "scea.dom.editors.child") { // Child value annotation ChildInfo element = type.GetChildInfo(name); if (element == null) { throw new AnnotationException("Type doesn't have this element"); } desc = new ChildPropertyDescriptor( displayName, element, category, description, readOnly, editor, typeConverter); } } return(desc); }
private void WalkParticle(XmlSchemaParticle particle, DomNodeType nodeType) { XmlSchemaElement element = particle as XmlSchemaElement; if (element != null) { XmlSchemaSimpleType simpleType = element.ElementSchemaType as XmlSchemaSimpleType; if (simpleType != null && element.MaxOccurs == 1) { XmlAttributeType attributeType = GetAttributeType(simpleType); string fieldName = GetFieldName(element.QualifiedName); XmlAttributeInfo attributeInfo = new XmlAttributeInfo(fieldName, attributeType); nodeType.Define(attributeInfo); m_annotations.Add(attributeInfo, GetAnnotation(element)); attributeInfo.IsElement = true; if (element.DefaultValue != null) { if (element.FixedValue != null) { throw new InvalidOperationException(string.Format("Schema element {0} cannot have both a default value and a fixed value", element.QualifiedName)); } attributeInfo.DefaultValue = attributeType.Convert(element.DefaultValue); } else if (element.FixedValue != null) { attributeInfo.DefaultValue = attributeType.Convert(element.FixedValue); } } else { DomNodeType childNodeType = null; if (simpleType != null) { bool firstTime; childNodeType = WrapSimpleType(simpleType, out firstTime); // The collada.xsd's ListOfUInts element breaks the generated Schema.cs file otherwise. if (firstTime) { // Add the value attribute XmlAttributeType valueAttributeType = GetAttributeType(simpleType); var valueAttributeInfo = new XmlAttributeInfo(string.Empty, valueAttributeType); childNodeType.Define(valueAttributeInfo); } } else { XmlSchemaComplexType complexType = element.ElementSchemaType as XmlSchemaComplexType; if (complexType != null) { childNodeType = GetNodeType(complexType, element); } } if (childNodeType != null) { int minOccurs = (int)Math.Min(element.MinOccurs, Int32.MaxValue); int maxOccurs = (int)Math.Min(element.MaxOccurs, Int32.MaxValue); if (particle.Parent is XmlSchemaChoice) { var parent = (XmlSchemaChoice)particle.Parent; if (parent.MinOccurs != 1) { minOccurs = (int)Math.Min(Math.Max(element.MinOccurs, parent.MinOccurs), Int32.MaxValue); } if (parent.MaxOccurs != 1) { maxOccurs = (int)Math.Min(Math.Max(element.MaxOccurs, parent.MaxOccurs), Int32.MaxValue); } } else if (particle.Parent is XmlSchemaSequence) { var parent = (XmlSchemaSequence)particle.Parent; if (parent.MinOccurs != 1) { minOccurs = (int)Math.Min(Math.Max(element.MinOccurs, parent.MinOccurs), Int32.MaxValue); } if (parent.MaxOccurs != 1) { maxOccurs = (int)Math.Min(Math.Max(element.MaxOccurs, parent.MaxOccurs), Int32.MaxValue); } } ChildInfo childInfo = new ChildInfo(GetFieldName(element.QualifiedName), childNodeType, maxOccurs > 1); if ((minOccurs > 0 || maxOccurs < Int32.MaxValue) && minOccurs <= maxOccurs) { childInfo.AddRule(new ChildCountRule(minOccurs, maxOccurs)); } // Check for substitution groups if (!element.RefName.IsEmpty) { m_refElements.Add(childInfo, element.RefName); } nodeType.Define(childInfo); m_annotations.Add(childInfo, GetAnnotation(element)); } } } else { XmlSchemaGroupBase grp = particle as XmlSchemaSequence; if (grp == null) { grp = particle as XmlSchemaChoice; } if (grp == null) { grp = particle as XmlSchemaAll; } if (grp != null) { foreach (XmlSchemaParticle subParticle in grp.Items) { WalkParticle(subParticle, nodeType); } } } }
/// <summary> /// Converts schemas to NodeTypes, AttributeTypes, and root elements</summary> /// <param name="schemaSet">Schemas to register</param> public void Load(XmlSchemaSet schemaSet) { if (!schemaSet.IsCompiled) { schemaSet.Compile(); } System.Collections.ICollection schemas = schemaSet.Schemas(); foreach (XmlSchema schema in schemas) { string targetNamespace = schema.TargetNamespace; if (string.IsNullOrEmpty(targetNamespace)) { throw new InvalidOperationException("Schema has no target namespace"); } // only register the schema once; targetNamespaces must be globally unique if (!m_typeCollections.ContainsKey(targetNamespace)) { XmlQualifiedName[] nameSpaces = schema.Namespaces.ToArray(); XmlSchemaTypeCollection typeCollection = new XmlSchemaTypeCollection(nameSpaces, targetNamespace, this); m_typeCollections.Add(targetNamespace, typeCollection); } } try { m_annotations = new Dictionary <NamedMetadata, IList <XmlNode> >(); m_typeNameSet = new HashSet <string>(); m_localElementSet = new Dictionary <XmlSchemaElement, XmlQualifiedName>(); // collect global element & type names so we do not generate local type names that collides with those foreach (XmlSchemaElement element in schemaSet.GlobalElements.Values) { m_typeNameSet.Add(element.QualifiedName.Name); } foreach (XmlSchemaType type in schemaSet.GlobalTypes.Values) { if (type is XmlSchemaComplexType) { m_typeNameSet.Add(type.Name); } } var substitutionGroups = new Multimap <XmlQualifiedName, ChildInfo>(); // Get types reachable from global elements foreach (XmlSchemaElement element in schemaSet.GlobalElements.Values) { XmlSchemaType type = element.ElementSchemaType; DomNodeType nodeType = GetNodeType(type, element); ChildInfo childInfo = new ChildInfo(GetFieldName(element.QualifiedName), nodeType); m_annotations.Add(childInfo, GetAnnotation(element)); // Keep list of substitution groups if (!element.SubstitutionGroup.IsEmpty) { substitutionGroups.Add(element.SubstitutionGroup, childInfo); } // only add root elements once; root element names must be globally unique string name = element.QualifiedName.ToString(); if (!m_rootElements.ContainsKey(name)) { m_rootElements[name] = childInfo; } } // Get global complex type definitions foreach (XmlSchemaType type in schemaSet.GlobalTypes.Values) { if (type is XmlSchemaComplexType) { GetNodeType(type, null); } } // Parse substitution groups foreach (var kvp in m_refElements) { XmlQualifiedName refName = kvp.Value; ChildInfo childInfo = kvp.Key; var substitutions = CreateSubstitutions(substitutionGroups, refName).ToArray(); if (substitutions.Length > 0) { childInfo.AddRule(new SubstitutionGroupChildRule(substitutions)); } } // Preserve annotation from any types that were redefined foreach (XmlSchema schema in schemas) { foreach (XmlSchemaObject schemaInclude in schema.Includes) { XmlSchemaRedefine schemaRedefine = schemaInclude as XmlSchemaRedefine; if (schemaRedefine != null) { MergeRedefinedTypeAnnotations(schemaRedefine); } } } // Sort DomNodeTypes, so that base types are always before derived types // Bucket sort by depth in the inheritance tree // Time: O(n * d) with n = number of DomNodeTypes, d = depth of inheritance tree var sortedTypes = new List <List <DomNodeType> >(); foreach (DomNodeType type in GetNodeTypes()) { // Get inheritance depth of current type int depth = 0; DomNodeType curType = type; while (curType != null && curType != DomNodeType.BaseOfAllTypes) { depth++; curType = curType.BaseType; } // We don't need to merge annotations for BaseAllTypes (level 0) // and its immediate child types (level 1) int idx = depth - 2; if (idx >= 0) { while (sortedTypes.Count <= idx) { sortedTypes.Add(new List <DomNodeType>()); } sortedTypes[idx].Add(type); } } // Merge type annotations with base type annotations foreach (var list in sortedTypes) { foreach (DomNodeType type in list) { if (type.BaseType != null && type.BaseType != DomNodeType.BaseOfAllTypes) { IList <XmlNode> baseAnnotations; IList <XmlNode> annotations; if (m_annotations.TryGetValue(type.BaseType, out baseAnnotations) && m_annotations.TryGetValue(type, out annotations)) { // Call protected virtual merge method - allowing clients to define if & how annotations are being merged IEnumerable <XmlNode> mergedAnnotations = MergeInheritedTypeAnnotations(baseAnnotations, annotations); m_annotations[type] = mergedAnnotations as IList <XmlNode> ?? mergedAnnotations.ToList(); } } } } // Call before the DomNodeTypes are frozen. Note that iterating through Attributes or // calling 'SetIdAttribute' freezes the attributes on DomNodeType. OnSchemaSetLoaded(schemaSet); // Set up ID attributes where xs:ID has been specified foreach (DomNodeType nodeType in GetNodeTypes()) { foreach (var attribute in nodeType.Attributes.OfType <XmlAttributeInfo>()) { if (((XmlAttributeType)attribute.Type).XmlTypeCode == XmlTypeCode.Id) { nodeType.SetIdAttribute(attribute.Name); } } } // Attach annotation as metadata to the associated type so that other classes can find it foreach (var keyValuePair in m_annotations) { if (keyValuePair.Value.Count > 0) { keyValuePair.Key.SetTag <IEnumerable <XmlNode> >(keyValuePair.Value); } } ParseAnnotations(schemaSet, m_annotations); // Call this after the ID attributes have been set and after the DomNodeTypes are frozen. OnDomNodeTypesFrozen(schemaSet); } finally { m_annotations = null; m_typeNameSet = null; m_localElementSet = null; } }
/// <summary> /// Reads the node specified by the child metadata</summary> /// <param name="nodeInfo">Child metadata for node</param> /// <param name="reader">XML reader</param> /// <returns>DomNode specified by the child metadata</returns> protected virtual DomNode ReadElement(ChildInfo nodeInfo, XmlReader reader) { // handle polymorphism, if necessary DomNodeType type = GetChildType(nodeInfo.Type, reader); int index = type.Name.LastIndexOf(':'); string typeNS = type.Name.Substring(0, index); DomNode node = new DomNode(type, nodeInfo); // read attributes while (reader.MoveToNextAttribute()) { if (reader.Prefix == string.Empty || reader.LookupNamespace(reader.Prefix) == typeNS) { AttributeInfo attributeInfo = type.GetAttributeInfo(reader.LocalName); if (attributeInfo != null) { string valueString = reader.Value; if (attributeInfo.Type.Type == AttributeTypes.Reference) { // save reference so it can be resolved after all nodes have been read m_nodeReferences.Add(new XmlNodeReference(node, attributeInfo, valueString)); } else { object value = attributeInfo.Type.Convert(valueString); node.SetAttribute(attributeInfo, value); } } } } // add node to map if it has an id if (node.Type.IdAttribute != null) { string id = node.GetId(); if (!string.IsNullOrEmpty(id)) { m_nodeDictionary[id] = node; // don't Add, in case there are multiple DomNodes with the same id } } reader.MoveToElement(); if (!reader.IsEmptyElement) { // read child elements while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element) { // look up metadata for this element ChildInfo childInfo = type.GetChildInfo(reader.LocalName); if (childInfo != null) { DomNode childObject = ReadElement(childInfo, reader); // at this point, child is a fully populated sub-tree if (childInfo.IsList) { node.GetChildList(childInfo).Add(childObject); } else { node.SetChild(childInfo, childObject); } } else { // try reading as an attribute AttributeInfo attributeInfo = type.GetAttributeInfo(reader.LocalName); if (attributeInfo != null) { reader.MoveToElement(); if (!reader.IsEmptyElement) { // read element text while (reader.Read()) { if (reader.NodeType == XmlNodeType.Text) { object value = attributeInfo.Type.Convert(reader.Value); node.SetAttribute(attributeInfo, value); // skip child elements, as this is an attribute value reader.Skip(); break; } if (reader.NodeType == XmlNodeType.EndElement) { break; } } reader.MoveToContent(); } } else { // skip unrecognized element reader.Skip(); // if that takes us to the end of the enclosing element, break if (reader.NodeType == XmlNodeType.EndElement) { break; } } } } else if (reader.NodeType == XmlNodeType.Text) { AttributeInfo attributeInfo = type.GetAttributeInfo(string.Empty); if (attributeInfo != null) { object value = attributeInfo.Type.Convert(reader.Value); node.SetAttribute(attributeInfo, value); } } else if (reader.NodeType == XmlNodeType.EndElement) { break; } } } reader.MoveToContent(); return(node); }
/// <summary> /// Constructor</summary> /// <param name="name">Field name</param> /// <param name="type">Field type</param> public ChildInfo( string name, DomNodeType type) : this(name, type, false) { }
/// <summary> /// Gets a derived node type, given a base type, namespace, and type name</summary> /// <param name="baseType">Base node type</param> /// <param name="ns">Type namespace</param> /// <param name="typeName">Type name</param> /// <returns>Derived node type</returns> protected virtual DomNodeType GetDerivedType(DomNodeType baseType, string ns, string typeName) { return(m_typeLoader.GetNodeType(ns + ":" + typeName)); }
/// <summary> /// Reads the node specified by the child metadata</summary> /// <param name="nodeInfo">Child metadata for node</param> /// <param name="reader">XML reader</param> /// <returns>DomNode specified by the child metadata</returns> protected virtual DomNode ReadElement(ChildInfo nodeInfo, XmlReader reader) { // handle polymorphism, if necessary DomNodeType type = null; var substitutionGroupRule = nodeInfo.Rules.OfType <SubstitutionGroupChildRule>().FirstOrDefault(); if (substitutionGroupRule != null) { foreach (var sub in substitutionGroupRule.Substitutions) { if (sub.Name == reader.LocalName) { type = sub.Type; break; } } if (type == null) { throw new InvalidOperationException("Could not match substitution group for child " + nodeInfo.Name); } } else { type = GetChildType(nodeInfo.Type, reader); } int index = type.Name.LastIndexOf(':'); string typeNS = type.Name.Substring(0, index); DomNode node = new DomNode(type, nodeInfo); // read attributes while (reader.MoveToNextAttribute()) { if (reader.Prefix == string.Empty || reader.LookupNamespace(reader.Prefix) == typeNS) { AttributeInfo attributeInfo = type.GetAttributeInfo(reader.LocalName); if (attributeInfo != null) { ReadAttribute(node, attributeInfo, reader.Value); } } } // add node to map if it has an id if (node.Type.IdAttribute != null) { string id = node.GetId(); if (!string.IsNullOrEmpty(id)) { m_nodeDictionary[id] = node; // don't Add, in case there are multiple DomNodes with the same id } } reader.MoveToElement(); if (!reader.IsEmptyElement) { // read child elements while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element) { // look up metadata for this element ChildInfo childInfo = type.GetChildInfo(reader.LocalName); if (childInfo == null) { // Try and get substitution group childInfo = GetSubsitutionGroup(type, reader.LocalName); } if (childInfo != null) { DomNode childNode = ReadElement(childInfo, reader); if (childNode != null) { // childNode is fully populated sub-tree if (childInfo.IsList) { node.GetChildList(childInfo).Add(childNode); } else { node.SetChild(childInfo, childNode); } } } else { // try reading as an attribute AttributeInfo attributeInfo = type.GetAttributeInfo(reader.LocalName); if (attributeInfo != null) { reader.MoveToElement(); if (!reader.IsEmptyElement) { // read element text while (reader.Read()) { if (reader.NodeType == XmlNodeType.Text) { ReadAttribute(node, attributeInfo, reader.Value); // skip child elements, as this is an attribute value reader.Skip(); break; } if (reader.NodeType == XmlNodeType.EndElement) { break; } } reader.MoveToContent(); } } else { // skip unrecognized element reader.Skip(); // if that takes us to the end of the enclosing element, break if (reader.NodeType == XmlNodeType.EndElement) { break; } } } } else if (reader.NodeType == XmlNodeType.Text) { AttributeInfo attributeInfo = type.GetAttributeInfo(string.Empty); if (attributeInfo != null) { ReadAttribute(node, attributeInfo, reader.Value); } } else if (reader.NodeType == XmlNodeType.EndElement) { break; } } } reader.MoveToContent(); return(node); }
/// <summary> /// Writes the attributes corresponding to the node</summary> /// <param name="node">DomNode to write</param> /// <param name="writer">The XML writer. See <see cref="T:System.Xml.XmlWriter"/></param> protected virtual void WriteAttributes(DomNode node, XmlWriter writer) { // write type name if this is a polymorphic type // if this node is substitution group element then ignore type name // unless it is a root node (for root node, substitution groups are ignored) DomNodeType type = node.Type; if (node.ChildInfo.Type != type && (IsRootNode(node) || node.ChildInfo.Rules.OfType <SubstitutionGroupChildRule>().FirstOrDefault() == null)) { string name = type.Name; int index = name.LastIndexOf(':'); if (index >= 0) { string typeName = name.Substring(index + 1, type.Name.Length - index - 1); string typeNS = name.Substring(0, index); string typePrefix = writer.LookupPrefix(typeNS); if (typePrefix == null) { typePrefix = GeneratePrefix(typeNS); writer.WriteAttributeString("xmlns", typePrefix, null, typeNS); } name = typeName; if (typePrefix != string.Empty) { name = typePrefix + ":" + typeName; } } writer.WriteAttributeString("xsi", "type", XmlSchema.InstanceNamespace, name); } // write attributes AttributeInfo valueAttribute = null; var attributesAsElements = new List <AttributeInfo>(); foreach (AttributeInfo attributeInfo in type.Attributes) { // if attribute is not the default, write it if (ShouldWriteAttribute(node, attributeInfo)) { if (attributeInfo.Name == string.Empty) { valueAttribute = attributeInfo; } else { if (PreserveSimpleElements) { var xmlAttributeInfo = attributeInfo as XmlAttributeInfo; if (xmlAttributeInfo != null && xmlAttributeInfo.IsElement) { attributesAsElements.Add(xmlAttributeInfo); continue; } } WriteXmlAttribute(node, attributeInfo, writer); } } } // write value if not the default if (valueAttribute != null) { string valueString = Convert(node, valueAttribute); writer.WriteString(valueString); } // write DOM attributes that were originally XML elements of a simple type foreach (AttributeInfo info in attributesAsElements) { writer.WriteStartElement(m_elementPrefix, info.Name, m_elementNS); string valueString = Convert(node, info); writer.WriteString(valueString); writer.WriteEndElement(); } }
/// <summary> /// Writes the element corresponding to the DomNode</summary> /// <param name="node">DomNode to write</param> protected virtual void WriteElement(DomNode node, XmlWriter writer) { string elementNS = m_typeCollection.TargetNamespace; int index = node.ChildInfo.Name.LastIndexOf(':'); if (index >= 0) { elementNS = node.ChildInfo.Name.Substring(0, index); } string elementPrefix = string.Empty; // is this the root DomNode? if (node.Parent == null) { elementPrefix = m_typeCollection.GetPrefix(elementNS); if (elementPrefix == null) { elementPrefix = GeneratePrefix(elementNS); } writer.WriteStartElement(elementPrefix, node.ChildInfo.Name, elementNS); // define the xsi namespace writer.WriteAttributeString("xmlns", "xsi", null, XmlSchema.InstanceNamespace); // define schema namespaces foreach (XmlQualifiedName name in m_typeCollection.Namespaces) { if (name.Name != elementPrefix) // don't redefine the element namespace { writer.WriteAttributeString("xmlns", name.Name, null, name.Namespace); } } } else { // not the root, so all schema namespaces have been defined elementPrefix = writer.LookupPrefix(elementNS); if (elementPrefix == null) { elementPrefix = GeneratePrefix(elementNS); } writer.WriteStartElement(elementPrefix, node.ChildInfo.Name, elementNS); } // write type name if this is a polymorphic type DomNodeType type = node.Type; if (node.ChildInfo.Type != type) { string name = type.Name; index = name.LastIndexOf(':'); if (index >= 0) { string typeName = name.Substring(index + 1, type.Name.Length - index - 1); string typeNS = name.Substring(0, index); string typePrefix = writer.LookupPrefix(typeNS); if (typePrefix == null) { typePrefix = GeneratePrefix(typeNS); writer.WriteAttributeString("xmlns", typePrefix, null, typeNS); } name = typeName; if (typePrefix != string.Empty) { name = typePrefix + ":" + typeName; } } writer.WriteAttributeString("xsi", "type", XmlSchema.InstanceNamespace, name); } // write attributes AttributeInfo valueAttribute = null; foreach (AttributeInfo attributeInfo in type.Attributes) { // if attribute is required, or not the default, write it if (/*attributeInfo.Required ||*/ !node.IsAttributeDefault(attributeInfo)) { if (attributeInfo.Name == string.Empty) { valueAttribute = attributeInfo; } else { object value = node.GetAttribute(attributeInfo); string valueString = null; if (attributeInfo.Type.Type == AttributeTypes.Reference) { // if reference is a valid node, convert to string DomNode refNode = value as DomNode; if (refNode != null) { valueString = GetNodeReferenceString(refNode, m_root, m_uri); } } if (valueString == null) { valueString = attributeInfo.Type.Convert(value); } writer.WriteAttributeString(attributeInfo.Name, valueString); } } } // write value if not the default if (valueAttribute != null) { object value = node.GetAttribute(valueAttribute); writer.WriteString(valueAttribute.Type.Convert(value)); } // write child elements foreach (ChildInfo childInfo in type.Children) { if (childInfo.IsList) { foreach (DomNode child in node.GetChildList(childInfo)) { WriteElement(child, writer); } } else { DomNode child = node.GetChild(childInfo); if (child != null) { WriteElement(child, writer); } } } writer.WriteEndElement(); }
private DomNodeType GetNodeType(XmlSchemaComplexType complexType, XmlSchemaElement element) { // get type name XmlQualifiedName name = complexType.QualifiedName; if (name.IsEmpty) // local type { name = GetLocalTypeName(element); } string typeName = name.ToString(); DomNodeType nodeType; if (!m_nodeTypes.TryGetValue(typeName, out nodeType)) { // build a new complex type and add it to the dictionary nodeType = new DomNodeType(typeName); m_nodeTypes.Add(typeName, nodeType); m_annotations.Add(nodeType, GetAnnotation(complexType)); DomNodeType baseType = null; XmlAttributeType valueType = null; XmlSchemaComplexType complexBaseType = GetBaseType(complexType); if (complexBaseType != null) { baseType = GetNodeType(complexBaseType, null); } XmlSchemaSimpleType simpleBase = complexType.BaseXmlSchemaType as XmlSchemaSimpleType; if (simpleBase != null) { valueType = GetAttributeType(simpleBase); } else if (complexType.IsMixed) { valueType = s_mixedTextFieldSimpleType; } WalkParticle(complexType.ContentTypeParticle, nodeType); if (valueType != null) { XmlAttributeInfo attributeInfo = new XmlAttributeInfo(string.Empty, valueType); nodeType.Define(attributeInfo); } // get XML attributes System.Collections.ICollection attributeUses = complexType.AttributeUses.Values; foreach (XmlSchemaAttribute attribute in attributeUses) { XmlAttributeType attributeType = GetAttributeType(attribute.AttributeSchemaType); string fieldName = GetFieldName(attribute.QualifiedName); XmlAttributeInfo attributeInfo = new XmlAttributeInfo(fieldName, attributeType); if (attribute.DefaultValue != null) { attributeInfo.DefaultValue = attributeType.Convert(attribute.DefaultValue); } m_annotations.Add(attributeInfo, GetAnnotation(attribute)); nodeType.Define(attributeInfo); } if (baseType != null) { nodeType.BaseType = baseType; } nodeType.IsAbstract = complexType.IsAbstract; } return(nodeType); }
/// <summary> /// Gets a derived node type given a base type, namespace, and type name</summary> /// <param name="baseType">Base node type</param> /// <param name="ns">Type namespace</param> /// <param name="typeName">Type name</param> /// <returns>Derived DomNodeType</returns> protected virtual DomNodeType GetDerivedType(DomNodeType baseType, string ns, string typeName) { return(m_typeCollection.GetNodeType(typeName)); }
/// <summary>Adds a node type to the ones defined by the schema</summary> /// <remarks>If the node type is already defined, it is overwritten</remarks> /// <param name="name">Name of node type</param> /// <param name="type">New node type</param> public void AddNodeType(string name, DomNodeType type) { m_nodeTypes[name] = type; }
private void WalkParticle(XmlSchemaParticle particle, DomNodeType nodeType) { XmlSchemaElement element = particle as XmlSchemaElement; if (element != null) { XmlSchemaSimpleType simpleType = element.ElementSchemaType as XmlSchemaSimpleType; if (simpleType != null && element.MaxOccurs == 1) { XmlAttributeType attributeType = GetAttributeType(simpleType); string fieldName = GetFieldName(element.QualifiedName); XmlAttributeInfo attributeInfo = new XmlAttributeInfo(fieldName, attributeType); nodeType.Define(attributeInfo); m_annotations.Add(attributeInfo, GetAnnotation(element)); attributeInfo.IsElement = true; if (element.DefaultValue != null) { if (element.FixedValue != null) { throw new InvalidOperationException(string.Format("Schema element {0} cannot have both a default value and a fixed value", element.QualifiedName)); } attributeInfo.DefaultValue = attributeType.Convert(element.DefaultValue); } else if (element.FixedValue != null) { attributeInfo.DefaultValue = attributeType.Convert(element.FixedValue); } } else { DomNodeType childNodeType = null; if (simpleType != null) { childNodeType = WrapSimpleType(simpleType); // Add the value attribute XmlAttributeType valueAttributeType = GetAttributeType(simpleType); var valueAttributeInfo = new XmlAttributeInfo(string.Empty, valueAttributeType); childNodeType.Define(valueAttributeInfo); } else { XmlSchemaComplexType complexType = element.ElementSchemaType as XmlSchemaComplexType; if (complexType != null) { childNodeType = GetNodeType(complexType, element); } } if (childNodeType != null) { int minOccurs = (int)Math.Min(element.MinOccurs, Int32.MaxValue); int maxOccurs = (int)Math.Min(element.MaxOccurs, Int32.MaxValue); // If <xs:choice> is within a <xs:sequence>, choose the most relaxed constraints. if (particle.Parent is XmlSchemaChoice && particle.Parent.Parent is XmlSchemaSequence) { XmlSchemaChoice parent = (XmlSchemaChoice)particle.Parent; int parentMinOccurs = (int)Math.Min(parent.MinOccurs, Int32.MaxValue); int parentMaxOccurs = (int)Math.Min(parent.MaxOccurs, Int32.MaxValue); minOccurs = Math.Min(parentMinOccurs, minOccurs); maxOccurs = Math.Max(parentMaxOccurs, maxOccurs); } ChildInfo childInfo = new ChildInfo(GetFieldName(element.QualifiedName), childNodeType, maxOccurs > 1); if (minOccurs > 0 || maxOccurs < Int32.MaxValue) { childInfo.AddRule(new ChildCountRule(minOccurs, maxOccurs)); } // Check for substitution groups if (!element.RefName.IsEmpty) { m_refElements.Add(childInfo, element.RefName); } nodeType.Define(childInfo); m_annotations.Add(childInfo, GetAnnotation(element)); } } } else { // if sequence, continue collecting elements XmlSchemaSequence sequence = particle as XmlSchemaSequence; if (sequence != null) { foreach (XmlSchemaParticle subParticle in sequence.Items) { WalkParticle(subParticle, nodeType); } } else { XmlSchemaChoice choice = particle as XmlSchemaChoice; if (choice != null) { // for now, treat choice as if it were a sequence foreach (XmlSchemaParticle subParticle in choice.Items) { WalkParticle(subParticle, nodeType); } } } } }