private static ChildInfo[] GetPath(DomNodeType type, string[] segments, int length) { ChildInfo[] result = new ChildInfo[length]; for (int i = 0; i < length; i++) { ChildInfo metaElement = type.GetChildInfo(segments[i]); if (metaElement == null) { throw new AnnotationException("Invalid path"); } result[i] = metaElement; type = metaElement.Type; } return(result); }
/// <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); }
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); }
/// <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> /// 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); }