private string _CreateSimpleArrayNode(string collectionName, bool appendNode)
        {
            Assert.IsNeitherNullNorEmpty(collectionName);
            Assert.AreEqual('[', collectionName[0]);

            var token = new PropertyNameInfo(collectionName);
            if (token.Type != PropertyNameTypes.SimpleExtensionCreationProperty)
            {
                throw new ArgumentException("The property name is improperly formatted for creating a new simple extension node.");
            }

            Assert.IsNeitherNullNorEmpty(token.Level1);
            Assert.IsNeitherNullNorEmpty(token.Level2);
            Assert.IsNeitherNullNorEmpty(token.SimpleExtensionNamespace);

            PropertyNode collectionNode = _EnsureSimpleCollection(token.SimpleExtensionNamespace, token.Level1);
            string xmlPrefix = collectionNode.ExtendedNamespacePrefix.Substring(1, collectionNode.ExtendedNamespacePrefix.Length - 2);
            XmlElement nodeElement = _document.CreateElement(xmlPrefix, token.Level2, collectionNode.ExtendedNamespace);

            // New nodes are set to nil.  Version is implicitly "1".
            XmlAttribute elementIdAttribute = _namespaceManager.CreateElementIdAttribute();
            elementIdAttribute.Value = Guid.NewGuid().ToString();
            XmlAttribute typeAttribute = _namespaceManager.CreateNodeTypeAttribute(SchemaStrings.SchemaTypeArrayNode);

            nodeElement.Attributes.Append(elementIdAttribute);
            nodeElement.Attributes.Append(typeAttribute);

            _namespaceManager.AddNilAttribute(nodeElement);
            _namespaceManager.UpdateVersionAndModificationDate(nodeElement);

            PropertyNode newNode = null;
            // Now modifying the DOM (probably modified it by creating the collection earlier, too...).
            _SetUnusableOnException(
                () =>
                {
                    if (appendNode)
                    {
                        collectionNode.XmlNode.AppendChild(nodeElement);
                    }
                    else
                    {
                        collectionNode.XmlNode.PrependChild(nodeElement);
                    }

                    // ??? _contactTree.AdjustTree();
                    newNode = new PropertyNode(nodeElement, collectionNode, appendNode) {Version = 1};
                    _FixupChildren(collectionNode, token.Level2);

                },
                null);

            _SuperExpensiveDeepValidate(this);
            
            Assert.IsNeitherNullNorEmpty(newNode.IContactName);
            return newNode.IContactName;
        }
Пример #2
0
 /// <summary>
 /// Does the given string represent a legal array-node property name?
 /// </summary>
 /// <param name="propertyName">The string to check.</param>
 /// <returns>Returns whether the string is a legal array node or level-3 property..</returns>
 public static bool IsPropertyValidNode(string propertyName)
 {
     var pni = new PropertyNameInfo(propertyName);
     Assert.AreNotEqual(pni.Type, PropertyNameTypes.None);
     return pni.Type == PropertyNameTypes.SchematizedNode || pni.Type == PropertyNameTypes.SimpleExtensionNode;
 }
        // TODO: Need to write the schema type on simple extensions.
        // TODO: Need to add valueType attribute for binary data.
        private void _SetString(string propertyName, string value, string valueType, string schemaType)
        {
            Assert.IsNeitherNullNorEmpty(propertyName);
            Assert.IsNeitherNullNorEmpty(value);
            Assert.IsNeitherNullNorEmpty(schemaType);
            Assert.Implies(schemaType == SchemaStrings.SchemaTypeBinary, !string.IsNullOrEmpty(valueType));
            Assert.Implies(schemaType != SchemaStrings.SchemaTypeBinary, null == valueType);

            var token = new PropertyNameInfo(propertyName);

            PropertyNode parentProperty;
            string elementName;
            string nodeName;

            switch (token.Type)
            {
                case PropertyNameTypes.SchematizedCollectionName:
                case PropertyNameTypes.SimpleExtensionNode:
                case PropertyNameTypes.SchematizedNode:
                case PropertyNameTypes.SimpleExtensionCreationProperty:
                    // None of these types of properties can have values set on them.
                    throw new ArgumentException("This type of property cannot have a value set to it.");

                case PropertyNameTypes.SchematizedHierarchicalProperty:
                    // If it's a hierarchical property, need to make sure that the parent node already exists.
                    nodeName = token.Level1 + "/" + token.Level2 + "[" + token.Index + "]";
                    parentProperty = _contactTree.Lookup.FindNode(nodeName, NodeTypes.Any);
                    if (null == parentProperty)
                    {
                        throw new PropertyNotFoundException("The node where the property is to be set doesn't exist.  The node needs to be created first.", nodeName);
                    }
                    elementName = token.Level3;
                    break;

                case PropertyNameTypes.SimpleExtensionHierarchicalProperty:
                    // If it's a hierarchical property, need to make sure that the parent node already exists.
                    nodeName = "[" + token.SimpleExtensionNamespace + "]" + token.Level1 + "/" + token.Level2 + "[" + token.Index + "]";
                    parentProperty = _contactTree.Lookup.FindNode(nodeName, NodeTypes.Any);
                    if (null == parentProperty)
                    {
                        throw new PropertyNotFoundException("The node where the property is to be set doesn't exist.  The node needs to be created first.", nodeName);
                    }
                    elementName = token.Level3;
                    break;

                case PropertyNameTypes.SchematizedTopLevelProperty:
                    // Nothing needs to be done for schematized top level properties.  Parent is the root Contact node.
                    parentProperty = _contactTree.ContactRoot;
                    elementName = token.Level1;
                    break;

                case PropertyNameTypes.SimpleExtensionTopLevel:
                    // the root is just the extension root.

                    parentProperty = _contactTree.ExtendedRoot;
                    elementName = token.Level1;
                    break;

                default:
                    Assert.Fail();
                    throw new ArgumentException("Invalid property name.", "propertyName");
            }

            Assert.IsNotNull(parentProperty);
            Assert.Implies(parentProperty.ContactNodeType != NodeTypes.ElementNode, parentProperty.ContactNodeType == NodeTypes.RootElement);

            // See if the node we're trying to write to already exists.
            // Otherwise we'll need to create it (and rollback its creation on failure).
            PropertyNode oldProperty = null;
            foreach (PropertyNode child in parentProperty.Children)
            {
                if (child.IContactName == propertyName)
                {
                    oldProperty = child;

                    // For simple extensions, make sure that if this is a top level property
                    if (child.ContactNodeType == NodeTypes.ElementCollection)
                    {
                        throw new ArgumentException("This property represents a collection and doesn't support having values set on it.");
                    }
                    // I think with the current implementation the XML could have been explicitly manipulated to violate this.
                    // Might need to make the conditions around this assert a bit more bullet-proof.
                    Assert.AreEqual(0, child.Children.Count);
                    break;
                }
            }

            XmlNode childNode;
            if (null == oldProperty)
            {
                if (string.IsNullOrEmpty(token.SimpleExtensionNamespace))
                {
                    childNode = _namespaceManager.CreateSchemaElement(elementName);
                }
                else
                {
                    childNode = _namespaceManager.CreateExtensionElement(token.SimpleExtensionNamespace, elementName);
                }
            }
            else
            {
                childNode = oldProperty.XmlNode.CloneNode(false);
                XmlUtil.RemoveNilAttribute(childNode);
            }

            _namespaceManager.UpdateVersionAndModificationDate(childNode);
            XmlText valueText = _document.CreateTextNode(value);
            childNode.AppendChild(valueText);

            if (schemaType == SchemaStrings.SchemaTypeBinary)
            {
                _namespaceManager.SetMimeTypeAttribute(childNode, valueType);
            }

            if (!string.IsNullOrEmpty(token.SimpleExtensionNamespace))
            {
                _namespaceManager.SetSchemaTypeAttribute(childNode, schemaType);
            }

            //bool wasParentNil = false;
            _SetUnusableOnException(
                () =>
                {
                    if (parentProperty.XsiNil)
                    {
                        //wasParentNil = true;
                        XmlUtil.RemoveNilAttribute(parentProperty.XmlNode);
                        parentProperty.XsiNil = false;
                    }
        
                    PropertyNode childProperty;
                    if (null == oldProperty)
                    {
                        parentProperty.XmlNode.PrependChild(childNode);

                        // will need to remove this from parentProperty if we fail.
                        childProperty = new PropertyNode(childNode, parentProperty, false, value, propertyName);
                    }
                    else
                    {
                        parentProperty.XmlNode.ReplaceChild(childNode, oldProperty.XmlNode);
                        //PropertyNode.RebuildSubtree(childNode, oldProperty);
                        childProperty = oldProperty.CloneForSwap(false, false, childNode);
                        childProperty.Value = value;

                        parentProperty.ReplaceChild(childProperty, oldProperty);
                    }

                    _ValidateDom();

                    _contactTree.Lookup.Replace(childProperty);

                    _SuperExpensiveDeepValidate(this);
                },
                null);
        }
Пример #4
0
        /// <summary>
        /// Tries to parse the index out of a property name that might represent an array node.
        /// </summary>
        /// <param name="propertyName">The array node property name that contains the index to parse.</param>
        /// <returns>The zero-based parsed index if this appears to be an array node.  Otherwise returns -1.</returns>
        public static int GetIndexFromNode(string propertyName)
        {
            var pni = new PropertyNameInfo(propertyName);
            Assert.AreNotEqual(pni.Type, PropertyNameTypes.None);

            if (pni.Type != PropertyNameTypes.SchematizedNode && pni.Type != PropertyNameTypes.SimpleExtensionNode)
            {
                return -1;
            }
            Assert.IsNeitherNullNorEmpty(pni.Index);

            int i;
            // PropertyNameInfo should have blocked negative values here.
            if (!Int32.TryParse(pni.Index, out i))
            {
                return -1;
            }
            Assert.IsTrue(i > 0);

            --i;

            return i;
        }