public void TestValidate() { DomNodeType childType = new DomNodeType("child"); DomNodeType parentType = new DomNodeType("parent"); ChildInfo childInfo = new ChildInfo("child", childType, true); parentType.Define(childInfo); DomNode parent = new DomNode(parentType); IList<DomNode> childList = parent.GetChildList(childInfo); DomNode child1 = new DomNode(childType); DomNode child2 = new DomNode(childType); DomNode child3 = new DomNode(childType); ChildCountRule test = new ChildCountRule(1, 2); // 0 children. Not valid. Assert.False(test.Validate(parent, null, childInfo)); // 1 child. Valid. childList.Add(child1); Assert.True(test.Validate(parent, null, childInfo)); // 2 children. Valid. childList.Add(child2); Assert.True(test.Validate(parent, null, childInfo)); // 3 children. Not valid. childList.Add(child3); Assert.False(test.Validate(parent, null, childInfo)); // 0 children. Not valid. childList.Clear(); Assert.False(test.Validate(parent, null, childInfo)); }
public void TestListConstructor() { DomNodeType type = new DomNodeType("child"); ChildInfo test = new ChildInfo("test", type, true); Assert.AreEqual(test.Name, "test"); Assert.AreEqual(test.Type, type); Assert.True(test.IsList); }
public void TestConstructor() { DomNodeType type = new DomNodeType("child"); ChildInfo info = new ChildInfo("test", type); DomNode test = new DomNode(type, info); Assert.AreSame(test.Type, type); Assert.AreSame(test.ChildInfo, info); }
public Slot(DomNode owner, ChildInfo childInfo) { if (owner == null || childInfo == null) throw new ArgumentNullException(); m_owner = owner; m_childInfo = childInfo; }
/// <summary> /// Constructor</summary> /// <param name="name">Property's display name</param> /// <param name="childInfo">ChildInfo identifying child</param> /// <param name="category">Category of property</param> /// <param name="description">Description of property</param> /// <param name="isReadOnly">Whether or not property is read-only</param> public ChildPropertyDescriptor( string name, ChildInfo childInfo, string category, string description, bool isReadOnly) : this(name, childInfo, category, description, isReadOnly, null, null) { }
public void TestEquality() { var attrType1 = new AttributeType("xkcd", typeof(string)); var attrInfo1 = new AttributeInfo("xkcd", attrType1); var domNodeType = new DomNodeType("WebComic", DomNodeType.BaseOfAllTypes); var childInfo1 = new ChildInfo("xkcd", domNodeType); attrInfo1.DefaultValue = "Firefly"; var desc1 = new ChildAttributePropertyDescriptor( "xkcd", attrInfo1, childInfo1, "Category 1", "A commonly used word or phrase in the xkcd comic", true); int originalHashCode = desc1.GetHashCode(); // test if two identically created property descriptors compare as being equal var desc2 = new ChildAttributePropertyDescriptor( "xkcd", attrInfo1, childInfo1, "Category 1", "A commonly used word or phrase in the xkcd comic", true); Assert.AreEqual(desc1, desc2); Assert.AreEqual(desc1.GetHashCode(), desc2.GetHashCode()); // test category being different; oddly, although I think they should not be considered equal, // the .Net PropertyDescriptor ignores the difference in category name. So, I'm guessing that // the AttributePropertyDescriptor should behave the same as PropertyDescriptor. var desc3 = new ChildAttributePropertyDescriptor( "xkcd", attrInfo1, childInfo1, "Category 2", "A commonly used word or phrase in the xkcd comic", true); Assert.AreEqual(desc1, desc3); Assert.AreEqual(desc1.GetHashCode(), desc3.GetHashCode()); // test description being different; similarly here, the .Net PropertyDescriptor doesn't care. var desc4 = new ChildAttributePropertyDescriptor( "xkcd", attrInfo1, childInfo1, "Category 1", "slightly different description", true); Assert.AreEqual(desc1, desc4); Assert.AreEqual(desc1.GetHashCode(), desc4.GetHashCode()); // test readOnly being different; ditto for read-only flag! var desc5 = new ChildAttributePropertyDescriptor( "xkcd", attrInfo1, childInfo1, "Category 1", "A commonly used word or phrase in the xkcd comic", false); Assert.AreEqual(desc1, desc5); Assert.AreEqual(desc1.GetHashCode(), desc5.GetHashCode()); // test that the hash code hasn't changed after using the AttributeInfo var attrInfo2 = new AttributeInfo("xkcd", attrType1); domNodeType.Define(attrInfo2); Assert.AreEqual(desc1.GetHashCode(), originalHashCode); // test that the hash code hasn't changed after creating a derived DomNodeType var derivedDomNodeType = new DomNodeType("ScientificWebComic", domNodeType); var derivedAttrInfo = new AttributeInfo("xkcd", attrType1); var derivedChildInfo = new ChildInfo("xkcd", derivedDomNodeType); derivedDomNodeType.Define(derivedAttrInfo); Assert.AreEqual(desc1.GetHashCode(), originalHashCode); // test that an AttributeInfo used in a derived DomNodeType doesn't change equality or hash code var desc6 = new ChildAttributePropertyDescriptor( "xkcd", derivedAttrInfo, derivedChildInfo, "Category 1", "A commonly used word or phrase in the xkcd comic", true); Assert.AreEqual(desc1, desc6); Assert.AreEqual(desc1.GetHashCode(), desc6.GetHashCode()); }
/// <summary> /// Constructor</summary> /// <param name="name">Value's display name</param> /// <param name="attributeInfos">An array of meta attributes in the collection</param> /// <param name="childInfo">Meta element identifying child that owns the attributes</param> /// <param name="category">Category of property</param> /// <param name="description">Description of property</param> /// <param name="isReadOnly">Whether or not property is read-only</param> public ChildAttributeCollectionPropertyDescriptor( string name, AttributeInfo[] attributeInfos, ChildInfo childInfo, string category, string description, bool isReadOnly) : this(name, attributeInfos, childInfo, category, description, isReadOnly, null, null) { }
public void TestChildParent() { DomNodeType type = new DomNodeType("type"); ChildInfo childInfo = new ChildInfo("child", type, true); type.Define(childInfo); DomNode child = new DomNode(type); DomNode parent = new DomNode(type); parent.GetChildList(childInfo).Add(child); Assert.AreSame(child.Parent, parent); }
/// <summary> /// Constructor</summary> /// <param name="parent">Node's parent</param> /// <param name="childInfo">Metadata for child</param> /// <param name="child">Child node</param> /// <param name="index">Node's index in parent</param> public ChildEventArgs( DomNode parent, ChildInfo childInfo, DomNode child, int index) { Parent = parent; ChildInfo = childInfo; Child = child; Index = index; }
/// <summary> /// Constructor</summary> /// <param name="name">Value's display name</param> /// <param name="attributeInfos">An array of meta attributes in the collection</param> /// <param name="childInfo">Meta element identifying child that owns the attributes</param> /// <param name="category">Category of property</param> /// <param name="description">Description of property</param> /// <param name="isReadOnly">Whether or not property is read-only</param> /// <param name="editor">The editor used to edit the property</param> /// <param name="typeConverter">The type converter used for this property</param> public ChildAttributeCollectionPropertyDescriptor( string name, AttributeInfo[] attributeInfos, ChildInfo childInfo, string category, string description, bool isReadOnly, object editor, TypeConverter typeConverter) : this(name, attributeInfos, childInfo, category, description, isReadOnly, editor, typeConverter, null) { }
/// <summary> /// Constructor</summary> /// <param name="name">Value's display name</param> /// <param name="attributeInfo">Attribute metadata</param> /// <param name="childInfo">ChildInfo identifying child</param> /// <param name="category">Category of property</param> /// <param name="description">Description of property</param> /// <param name="isReadOnly">Whether or not property is read-only</param> /// <param name="editor">The editor used to edit the property</param> public ChildAttributePropertyDescriptor( string name, AttributeInfo attributeInfo, ChildInfo childInfo, string category, string description, bool isReadOnly, object editor) : this(name, attributeInfo, childInfo, category, description, isReadOnly, editor, null) { }
/// <summary> /// Adds OSC addresses (one for the x-coordinate and one for the y-coordinate) for a list /// of DOM children that have attributes that are arrays of floats. Each array of floats /// represents a 2D point where the first float is the x coordinate and the second float /// is the y coordinate.</summary> /// <param name="childInfo">The child info which defines the list of children of a selected DomNode</param> /// <param name="childAttributeDesc">The attribute on each child that defines the array of floats</param> /// <param name="oscAddress">The base OSC address to use. "/x" and "/y" will be appended for /// the x-coordinate array and the y-coordinate array, which is how Lemur sends and receives /// 2-D point arrays.</param> /// <returns>The base OSC address, with possible changes to make it legal.</returns> public string Add2DPointProperty(ChildInfo childInfo, AttributePropertyDescriptor childAttributeDesc, string oscAddress) { oscAddress = OscServices.FixPropertyAddress(oscAddress); var xCoordDesc = new ChildListFloatingPointArrayDesc(childInfo, childAttributeDesc, 0); AddPropertyAddress(xCoordDesc, oscAddress + "/x"); var yCoordDesc = new ChildListFloatingPointArrayDesc(childInfo, childAttributeDesc, 1); AddPropertyAddress(yCoordDesc, oscAddress + "/y"); return oscAddress; }
/// <summary> /// Checks that the parent DomNode has the correct # of children of the given type</summary> /// <param name="parent">Parent DOM node</param> /// <param name="child">Child DOM node; ignored</param> /// <param name="childInfo">Child relationship info</param> /// <returns>True, iff 'parent' has a valid number of children of the type associated /// with 'childInfo'</returns> public override bool Validate(DomNode parent, DomNode child, ChildInfo childInfo) { if (childInfo.IsList) { IList<DomNode> childList = parent.GetChildList(childInfo); int count = childList.Count; return count >= m_min && count <= m_max; } // singleton child references can always be set return true; }
/// <summary> /// Constructor</summary> /// <param name="name">Value's display name</param> /// <param name="childInfo">ChildInfo identifying child</param> /// <param name="category">Category of property</param> /// <param name="description">Description of property</param> /// <param name="isReadOnly">Whether or not property is read-only</param> /// <param name="editor">The editor used to edit the property</param> /// <param name="typeConverter">The type converter used for this property</param> public ChildPropertyDescriptor( string name, ChildInfo childInfo, string category, string description, bool isReadOnly, object editor, TypeConverter typeConverter) : base(name, typeof(DomNode), category, description, isReadOnly, editor, typeConverter) { m_childInfo = childInfo; }
public void TestDescendantGetRoot() { DomNodeType type = new DomNodeType("type"); ChildInfo childInfo = new ChildInfo("child", type, true); type.Define(childInfo); DomNode child = new DomNode(type); DomNode parent = new DomNode(type); DomNode grandparent = new DomNode(type); parent.GetChildList(childInfo).Add(child); grandparent.GetChildList(childInfo).Add(parent); Assert.AreSame(child.GetRoot(), grandparent); }
/// <summary> /// Constructor</summary> /// <param name="name">Value's display name</param> /// <param name="attributeInfo">Attribute metadata</param> /// <param name="childInfo">ChildInfo identifying child</param> /// <param name="category">Category of property</param> /// <param name="description">Description of property</param> /// <param name="isReadOnly">Whether or not property is read-only</param> /// <param name="editor">The editor used to edit the property</param> /// <param name="typeConverter">The type converter used for this property</param> public ChildAttributePropertyDescriptor( string name, AttributeInfo attributeInfo, ChildInfo childInfo, string category, string description, bool isReadOnly, object editor, TypeConverter typeConverter) : base(name, attributeInfo, category, description, isReadOnly, editor, typeConverter) { m_childPath = new[] { childInfo }; }
public void TestValidation() { DomNodeType type = new DomNodeType("child"); ChildInfo test = new ChildInfo("test", type); CollectionAssert.IsEmpty(test.Rules); var rule = new SimpleChildRule(); test.AddRule(rule); Utilities.TestSequenceEqual(test.Rules, rule); Assert.True(test.Validate(null, null)); Assert.True(rule.Validated); }
public void TestGetPath() { DomNodeType type = new DomNodeType("type"); ChildInfo childInfo = new ChildInfo("child", type, true); type.Define(childInfo); DomNode child = new DomNode(type); DomNode parent = new DomNode(type); DomNode grandparent = new DomNode(type); parent.GetChildList(childInfo).Add(child); grandparent.GetChildList(childInfo).Add(parent); Utilities.TestSequenceEqual(child.GetPath(), grandparent, parent, child); Utilities.TestSequenceEqual(parent.GetPath(), grandparent, parent); Utilities.TestSequenceEqual(grandparent.GetPath(), grandparent); }
public TestValidator() { // define a tree of validation contexts m_childType = new DomNodeType("test"); m_stringAttrInfo = GetStringAttribute("string"); m_childType.Define(m_stringAttrInfo); m_refAttrInfo = GetRefAttribute("ref"); m_childType.Define(m_refAttrInfo); m_childInfo = new ChildInfo("child", m_childType); m_childType.Define(m_childInfo); m_childType.Define(new ExtensionInfo<ValidationContext>()); // define a distinct root type with the validator m_rootType = new DomNodeType("root"); m_rootType.BaseType = m_childType; m_rootType.Define(new ExtensionInfo<Validator>()); IEnumerable<AttributeInfo> attributes = m_rootType.Attributes; // freezes the types }
public void Remove(DomNode parent, DomNode child, ChildInfo chInfo) { NativeObjectAdapter childObject = child.As<NativeObjectAdapter>(); NativeObjectAdapter parentObject = parent.As<NativeObjectAdapter>(); object listIdObj = chInfo.GetTag(NativeAnnotations.NativeElement); if (childObject == null || parentObject == null || listIdObj == null) return; uint listId = (uint)listIdObj; uint typeId = (uint)chInfo.DefiningType.GetTag(NativeAnnotations.NativeType); ulong parentId = parentObject.InstanceId; ulong childId = childObject.InstanceId; GameEngine.ObjectRemoveChild(typeId, listId, parentId, childId); if (ManageNativeObjectLifeTime) { GameEngine.DestroyObject(childObject); } }
protected DomNodeType RootType;//derives from ChildType public TestValidator() { // define a tree of validation contexts ChildType = new DomNodeType("test"); StringAttrInfo = GetStringAttribute("string"); ChildType.Define(StringAttrInfo); RefAttrInfo = GetRefAttribute("ref"); ChildType.Define(RefAttrInfo); ChildInfo = new ChildInfo("child", ChildType); ChildType.Define(ChildInfo); ChildType.Define(new ExtensionInfo<ValidationContext>()); // define a distinct root type with the validator RootType = new DomNodeType("root"); RootType.BaseType = ChildType; RootType.Define(new ExtensionInfo<Validator>()); AttributeInfo overriddenInfo = GetStringAttribute("string"); RootType.Define(overriddenInfo); IEnumerable<AttributeInfo> attributes = RootType.Attributes; // freezes the types }
public void Insert(DomNode parent, DomNode child, ChildInfo chInfo, int index) { NativeObjectAdapter childObject = child.As<NativeObjectAdapter>(); NativeObjectAdapter parentObject = parent.As<NativeObjectAdapter>(); object listIdObj = chInfo.GetTag(NativeAnnotations.NativeElement); if (childObject == null || parentObject == null || listIdObj == null) return; if (chInfo.IsList && index >= (parent.GetChildList(chInfo).Count - 1)) index = -1; if (ManageNativeObjectLifeTime) { GameEngine.CreateObject(childObject); childObject.UpdateNativeOjbect(); } System.Diagnostics.Debug.Assert(childObject.InstanceId != 0); uint listId = (uint)listIdObj; uint typeId = (uint)chInfo.DefiningType.GetTag(NativeAnnotations.NativeType); ulong parentId = parentObject.InstanceId; ulong childId = childObject.InstanceId; if (index >= 0) { GameEngine.ObjectInsertChild(typeId, listId, parentId, childId, index); } else { GameEngine.ObjectAddChild(typeId, listId, parentId, childId); } foreach (var node in child.Children) { Insert(child, node, node.ChildInfo, -1); // use -1 for index to indicate an append operation. } }
public TestDataValidator() { m_childType = new DomNodeType("child"); m_parentType = new DomNodeType("parent"); m_parentType.Define(new ExtensionInfo<ValidationContext>()); m_parentType.Define(new ExtensionInfo<DataValidator>()); m_childCountRule = new ChildCountRule(2, 3); m_childInfo = new ChildInfo("child", m_childType, true); m_parentType.Define(m_childInfo); m_childInfo.AddRule(m_childCountRule); m_parent = new DomNode(m_parentType); m_parent.InitializeExtensions(); m_validationContext = m_parent.As<ValidationContext>(); m_child1 = new DomNode(m_childType); m_child2 = new DomNode(m_childType); m_child3 = new DomNode(m_childType); m_child4 = new DomNode(m_childType); }
/// <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> /// Parses annotations in schema sets. Override this to handle custom annotations.</summary> /// <param name="schemaSet">XML schema sets being loaded</param> /// <param name="annotations">Dictionary of annotations in schema</param> protected virtual void ParseAnnotations( XmlSchemaSet schemaSet, IDictionary <NamedMetadata, IList <XmlNode> > annotations) { // Inspect root types for the legacy annotation specifying id attribute // Get types reachable from global elements foreach (XmlSchemaElement element in schemaSet.GlobalElements.Values) { ChildInfo childInfo = GetRootElement(element.QualifiedName.ToString()); IList <XmlNode> xmlNodes; if (annotations.TryGetValue(childInfo.Type, out xmlNodes)) { string idAttribute = FindAttribute(xmlNodes, "idAttribute", "name"); if (idAttribute != null) { foreach (DomNodeType type in GetNodeTypes(element.QualifiedName.Namespace)) { type.SetIdAttribute(idAttribute); } } } } }
/// <summary> /// Starts writing an element for the given DomNode</summary> /// <param name="node">DomNode to write</param> /// <param name="writer">The XML writer. See <see cref="T:System.Xml.XmlWriter"/></param> protected void WriteStartElement(DomNode node, XmlWriter writer) { // It's possible to create DomNodes with no ChildInfo, and if the DomNode is never // parented, then its ChildInfo property will still be null. We could try to search // for a compatible root element in the m_typeCollection, but that's more code. if (node.ChildInfo == null) { throw new InvalidOperationException( "Please check your document's creation method to ensure that the root DomNode's" + " constructor was given a ChildInfo."); } // writes the start of an element m_elementNS = m_typeCollection.TargetNamespace; int index = node.ChildInfo.Type.Name.LastIndexOf(':'); if (index >= 0) { m_elementNS = node.ChildInfo.Type.Name.Substring(0, index); } m_elementPrefix = string.Empty; // is this the root DomNode (the one passed to Write)? if (IsRootNode(node)) { m_elementPrefix = m_typeCollection.GetPrefix(m_elementNS); if (m_elementPrefix == null) { m_elementPrefix = GeneratePrefix(m_elementNS); } writer.WriteStartElement(m_elementPrefix, node.ChildInfo.Name, m_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 != m_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 m_elementPrefix = writer.LookupPrefix(m_elementNS); ChildInfo actualChildInfo = node.ChildInfo; // Check for substitutions. They're not mandatory if the node type is an exact match to the child info type. // http://www.w3schools.com/schema/schema_complex_subst.asp if (node.Type != node.ChildInfo.Type) { var substitutionGroupRule = node.ChildInfo.Rules.OfType <SubstitutionGroupChildRule>().FirstOrDefault(); if (substitutionGroupRule != null) { ChildInfo substituteChildInfo = node.Type.Lineage.Join(substitutionGroupRule.Substitutions, n => n.Name, s => s.Type.Name, (n, s) => s ).FirstOrDefault(); if (substituteChildInfo == null) { throw new InvalidOperationException("No suitable Substitution Group found for node " + node); } actualChildInfo = substituteChildInfo; m_elementNS = m_typeCollection.TargetNamespace; index = substituteChildInfo.Type.Name.LastIndexOf(':'); if (index >= 0) { m_elementNS = substituteChildInfo.Type.Name.Substring(0, index); } // It is possible that an element of this namespace has not // yet been written. If the lookup fails then get the prefix from // the type collection. m_elementPrefix = writer.LookupPrefix(m_elementNS); if (m_elementPrefix == null) { m_elementPrefix = m_typeCollection.GetPrefix(m_elementNS); } } } if (m_elementPrefix == null) { m_elementPrefix = GeneratePrefix(m_elementNS); } writer.WriteStartElement(m_elementPrefix, actualChildInfo.Name, m_elementNS); } }
/// <summary> /// Gets the root element metadata for the reader's current XML node</summary> /// <param name="reader">XML reader</param> /// <param name="rootUri">URI of XML data</param> /// <returns>Root element metadata for the reader's current XML node</returns> protected virtual ChildInfo CreateRootElement(XmlReader reader, Uri rootUri) { ChildInfo rootElement = m_typeCollection.GetRootElement(reader.LocalName); return(rootElement); }
public override bool Validate(DomNode parent, DomNode child, ChildInfo childInfo) { return(m_substitutions.Any(x => x.Type == child.Type)); }
public void TestGetDescendantInfo() { DomNodeType grandchildType = new DomNodeType("grandchild"); ChildInfo grandChildInfo = new ChildInfo("grandChild", grandchildType); DomNodeType childType = new DomNodeType("child"); childType.Define(grandChildInfo); Assert.Null(childType.GetDescendantInfo(string.Empty)); Assert.Null(childType.GetDescendantInfo("foo")); Assert.AreSame(childType.GetDescendantInfo("grandChild"), grandChildInfo); ChildInfo childInfo = new ChildInfo("child", childType); DomNodeType parentType = new DomNodeType("parent"); parentType.Define(childInfo); Assert.AreSame(parentType.GetDescendantInfo("child"), childInfo); Assert.AreSame(parentType.GetDescendantInfo("child:grandChild"), grandChildInfo); }
/// <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); }
public void TestInheritedChildInfo() { ChildInfo info = new ChildInfo("foo", new DomNodeType("foo")); DomNodeType test = new DomNodeType( "test", null, EmptyEnumerable<AttributeInfo>.Instance, new ChildInfo[] { info }, EmptyEnumerable<ExtensionInfo>.Instance); DomNodeType child = new DomNodeType("child"); child.BaseType = test; ChildInfo inherited = child.GetChildInfo("foo"); Assert.AreEqual(inherited.OwningType, test); Assert.AreEqual(inherited.DefiningType, test); Assert.True(inherited.Equivalent(info)); Assert.True(info.Equivalent(inherited)); }
public void TestOverriddenChildInfo() { DomNodeType childType = new DomNodeType("foo"); ChildInfo info = new ChildInfo("foo", childType); DomNodeType test = new DomNodeType( "test", null, EmptyEnumerable<AttributeInfo>.Instance, new ChildInfo[] { info }, EmptyEnumerable<ExtensionInfo>.Instance); ChildInfo overridden = new ChildInfo("foo", childType); DomNodeType child = new DomNodeType("child", test, EmptyEnumerable<AttributeInfo>.Instance, new ChildInfo[] { overridden }, EmptyEnumerable<ExtensionInfo>.Instance); Assert.AreSame(child.GetChildInfo("foo"), overridden); Assert.AreEqual(overridden.OwningType, child); Assert.AreEqual(overridden.DefiningType, test); Assert.True(info.Equivalent(overridden)); Assert.True(overridden.Equivalent(info)); Assert.True(test.IsValid(overridden)); Assert.True(child.IsValid(info)); }
public static Settings New(ChildInfo childInfo) { DomNode node = new DomNode(Schema.settingsType.Type, childInfo); return node.Cast<Settings>(); }
public void TestCustomChildInfo() { DomNodeType type = new DomNodeType("foo"); ChildInfo info = new ChildInfo("foo", type); DomNodeType test = new DomNodeType( "test", null, EmptyEnumerable<AttributeInfo>.Instance, new ChildInfo[] { info }, EmptyEnumerable<ExtensionInfo>.Instance); Utilities.TestSequenceEqual(test.Children, info); Assert.True(test.IsValid(info)); Assert.AreSame(test.GetChildInfo("foo"), info); // check that type is now frozen Assert.Throws<InvalidOperationException>(delegate { test.Define(new ChildInfo("notFoo", type)); }); Assert.AreEqual(info.OwningType, test); Assert.AreEqual(info.DefiningType, test); Assert.Null(test.GetChildInfo("bar")); }
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); } } } } }
/// <summary> /// Sets the child of our adapted DomNode to a new DomNode</summary> /// <param name="childInfo">Metadata to indicate the child</param> /// <param name="value">Any IAdaptable, such as DomNodeAdapter, DomNode, or IAdapter</param> protected void SetChild(ChildInfo childInfo, IAdaptable value) { DomNode child = value.As <DomNode>(); DomNode.SetChild(childInfo, child); }
/// <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; } }
public void TestCopy_MultipleNodes() { DomNodeType type = new DomNodeType("type"); ChildInfo info = new ChildInfo("child", type); ChildInfo infoList = new ChildInfo("childList", type, true); type.Define(info); type.Define(infoList); ChildInfo rootInfo = new ChildInfo("root", type, true); DomNode test = new DomNode(type, rootInfo); DomNode child1 = new DomNode(type); test.SetChild(info, child1); DomNode child2 = new DomNode(type); DomNode child3 = new DomNode(type); IList<DomNode> list = test.GetChildList(infoList); list.Add(child2); list.Add(child3); DomNode[] result = DomNode.Copy(new DomNode[] { test }); Assert.AreEqual(result.Length, 1); Assert.True(Equals(result[0], test)); DomNode singleResult = DomNode.Copy(test); Assert.True(Equals(singleResult, test)); }
public DomXmlReader(ChildInfo rootNodeInfo, DomNodeTypeCollection typeCollection) { m_typeCollection = typeCollection; m_rootNodeInfo = rootNodeInfo; }
/// <summary> /// Constructor</summary> /// <param name="node">DomNode whose children are adapted by this</param> /// <param name="childInfo">Metadata indicating which child list to wrap</param> public DomNodeListAdapter(DomNode node, ChildInfo childInfo) { m_nodes = node.GetChildList(childInfo); }
/// <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); }
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); } } } }
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); }
public void TestChildRemoveEvents() { DomNodeType type = new DomNodeType("type"); ChildInfo info = new ChildInfo("child", type); ChildInfo infoList = new ChildInfo("childList", type, true); type.Define(info); type.Define(infoList); DomNode test = new DomNode(type); test.ChildRemoving += new EventHandler<ChildEventArgs>(test_ChildRemoving); test.ChildRemoved += new EventHandler<ChildEventArgs>(test_ChildRemoved); // test child DomNode child = new DomNode(type); test.SetChild(info, child); ChildRemovingArgs = null; ChildRemovedArgs = null; test.SetChild(info, null); ChildEventArgs expected = new ChildEventArgs(test, info, child, 0); Assert.True(Equals(ChildRemovingArgs, expected)); Assert.True(Equals(ChildRemovedArgs, expected)); // test inserting a child when there is one there already test.SetChild(info, child); DomNode newChild = new DomNode(type); ChildRemovingArgs = null; ChildRemovedArgs = null; test.SetChild(info, newChild); expected = new ChildEventArgs(test, info, child, 0); Assert.True(Equals(ChildRemovingArgs, expected)); Assert.True(Equals(ChildRemovedArgs, expected)); // test child list IList<DomNode> list = test.GetChildList(infoList); DomNode child2 = new DomNode(type); list.Add(child2); DomNode child3 = new DomNode(type); list.Add(child3); ChildRemovingArgs = null; ChildRemovedArgs = null; list.Remove(child3); expected = new ChildEventArgs(test, infoList, child3, 1); Assert.True(Equals(ChildRemovingArgs, expected)); Assert.True(Equals(ChildRemovedArgs, expected)); ChildRemovingArgs = null; ChildRemovedArgs = null; list.Remove(child2); expected = new ChildEventArgs(test, infoList, child2, 0); Assert.True(Equals(ChildRemovingArgs, expected)); Assert.True(Equals(ChildRemovedArgs, expected)); }
/// <summary> /// Gets the children of our adapted DomNode</summary> /// <typeparam name="T">The type to adapt each child to</typeparam> /// <param name="childInfo">Metadata to indicate the child list</param> /// <returns>Wrapper that adapts a node child list to a list of T items</returns> protected IList <T> GetChildList <T>(ChildInfo childInfo) where T : class { return(new DomNodeListAdapter <T>(DomNode, childInfo)); }