/// <summary> /// Inserts the specified element immediately before the specified reference element. /// </summary> /// <param name="newChild">The OpenXmlElement to insert.</param> /// <param name="refChild">The OpenXmlElement that is in the reference node.</param> /// <returns>The OpenXmlElement that was inserted.</returns> /// <remarks>Returns null if newChild equals null.</remarks> public override T InsertBefore <T>(T newChild, OpenXmlElement refChild) { if (newChild == null) { // throw new ArgumentNullException(nameof(newChild)); return(null); } if (newChild.Parent != null) { throw new InvalidOperationException(ExceptionMessages.ElementIsPartOfTree); } if (refChild == null) { return(AppendChild(newChild)); } if (refChild != null && refChild.Parent != this) { throw new InvalidOperationException(); } ElementInsertingEvent(newChild); OpenXmlElement prevNode = newChild; OpenXmlElement nextNode = refChild; Debug.Assert(nextNode != null); Debug.Assert(prevNode != null); if (nextNode == FirstChild) { prevNode.next = nextNode; _lastChild.next = prevNode; } else { OpenXmlElement previousSibling = nextNode.PreviousSibling(); prevNode.next = nextNode; previousSibling.next = prevNode; } newChild.Parent = this; // SetOwner(newChild); ElementInsertedEvent(newChild); return(newChild); }
private protected void SetElement <T>(int sequenceNumber, T newChild) where T : OpenXmlElement { switch (OpenXmlCompositeType) { case OpenXmlCompositeType.Other: throw new InvalidOperationException(); case OpenXmlCompositeType.OneAll: { T child = GetElement <T>(sequenceNumber); if (child != null) { // remove the old one RemoveChild(child); } if (newChild != null) { AppendChild(newChild); } } // TODO: should we handle error case? // 1: there are more than 1 elements for a type? // 2: there are more than 2 elements? // 3. there are other elements other than allowed children? break; case OpenXmlCompositeType.OneChoice: { OpenXmlElement child = FirstChild; OpenXmlElement previousChild = null; // skip unknown element and MiscNode while (child != null && !IsKnownElement(child)) { previousChild = child; child = child.NextSibling(); } OpenXmlElement next = null; while (child != null) { next = child.NextSibling(); // remove all exist elements if (IsKnownElement(child)) { RemoveChild(child); } child = next; } if (newChild != null) { InsertAfter(newChild, previousChild); } } // TODO: should we handle error case? // 1: there are more than 1 elements for a type? // 2: there are more than 2 elements? // 3. there are other elements other than allowed children? break; case OpenXmlCompositeType.OneSequence: { OpenXmlElement child = FirstChild; OpenXmlElement prev = null; while (child != null) { if (IsKnownElement(child)) { int childSequenceNumber = GetSequenceNumber(child); if (childSequenceNumber == sequenceNumber) { // remove the old one if (child is T) { // insert the new element after the previous. prev = child.PreviousSibling(); RemoveChild(child); break; } else { // same tag name, but wrong type, see bug 448241 prev = child; } } else if (childSequenceNumber > sequenceNumber) { break; } else { // always insert after the first known element prev = child; // continue search } } // continue search child = child.NextSibling(); } if (newChild != null) { InsertAfter(newChild, prev); } } // TODO: should we handle error case? // 1: there are more than 1 elements for a type? // 2: there are more than 2 elements? // 3. there are other elements other than allowed children? break; } }