| /******************************************************************************* | |
| * You may amend and distribute as you like, but don't remove this header! | |
| * | |
| * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. | |
| * See http://www.codeplex.com/EPPlus for details. | |
| * | |
| * Copyright (C) 2011 Jan Källman | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
| * See the GNU Lesser General Public License for more details. | |
| * | |
| * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php | |
| * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html | |
| * | |
| * All code and executables are provided "as is" with no warranty either express or implied. | |
| * The author accepts no liability for any damage or loss of business that this product may cause. | |
| * | |
| * Code change notes: | |
| * | |
| * Author Change Date | |
| * ****************************************************************************** | |
| * Jan Källman Initial Release 2009-10-01 | |
| * Jan Källman License changed GPL-->LGPL 2011-12-27 | |
| * Eyal Seagull Add "CreateComplexNode" 2012-04-03 | |
| * Eyal Seagull Add "DeleteTopNode" 2012-04-13 | |
| *******************************************************************************/ | |
| using System; | |
| using System.Collections.Generic; | |
| using System.Text; | |
| using System.Xml; | |
| using OfficeOpenXml.Style; | |
| using System.Globalization; | |
| using System.IO; | |
| namespace OfficeOpenXml | |
| { | |
| /// <summary> | |
| /// Help class containing XML functions. | |
| /// Can be Inherited | |
| /// </summary> | |
| public abstract class XmlHelper | |
| { | |
| internal delegate int ChangedEventHandler(StyleBase sender, Style.StyleChangeEventArgs e); | |
| internal XmlHelper(XmlNamespaceManager nameSpaceManager) | |
| { | |
| TopNode = null; | |
| NameSpaceManager = nameSpaceManager; | |
| } | |
| internal XmlHelper(XmlNamespaceManager nameSpaceManager, XmlNode topNode) | |
| { | |
| TopNode = topNode; | |
| NameSpaceManager = nameSpaceManager; | |
| } | |
| //internal bool ChangedFlag; | |
| internal XmlNamespaceManager NameSpaceManager { get; set; } | |
| internal XmlNode TopNode { get; set; } | |
| string[] _schemaNodeOrder = null; | |
| /// <summary> | |
| /// Schema order list | |
| /// </summary> | |
| internal string[] SchemaNodeOrder | |
| { | |
| get | |
| { | |
| return _schemaNodeOrder; | |
| } | |
| set | |
| { | |
| _schemaNodeOrder = value; | |
| } | |
| } | |
| internal XmlNode CreateNode(string path) | |
| { | |
| if (path == "") | |
| return TopNode; | |
| else | |
| return CreateNode(path, false); | |
| } | |
| internal XmlNode CreateNode(string path, bool insertFirst) | |
| { | |
| XmlNode node = TopNode; | |
| XmlNode prependNode = null; | |
| foreach (string subPath in path.Split('/')) | |
| { | |
| XmlNode subNode = node.SelectSingleNode(subPath, NameSpaceManager); | |
| if (subNode == null) | |
| { | |
| string nodeName; | |
| string nodePrefix; | |
| string nameSpaceURI = ""; | |
| string[] nameSplit = subPath.Split(':'); | |
| if (SchemaNodeOrder != null && subPath[0] != '@') | |
| { | |
| insertFirst = false; | |
| prependNode = GetPrependNode(subPath, node); | |
| } | |
| if (nameSplit.Length > 1) | |
| { | |
| nodePrefix = nameSplit[0]; | |
| if (nodePrefix[0] == '@') nodePrefix = nodePrefix.Substring(1, nodePrefix.Length - 1); | |
| nameSpaceURI = NameSpaceManager.LookupNamespace(nodePrefix); | |
| nodeName = nameSplit[1]; | |
| } | |
| else | |
| { | |
| nodePrefix = ""; | |
| nameSpaceURI = ""; | |
| nodeName = nameSplit[0]; | |
| } | |
| if (subPath.StartsWith("@")) | |
| { | |
| XmlAttribute addedAtt = node.OwnerDocument.CreateAttribute(subPath.Substring(1, subPath.Length - 1), nameSpaceURI); //nameSpaceURI | |
| node.Attributes.Append(addedAtt); | |
| } | |
| else | |
| { | |
| if (nodePrefix == "") | |
| { | |
| subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceURI); | |
| } | |
| else | |
| { | |
| if (nodePrefix == "" || (node.OwnerDocument != null && node.OwnerDocument.DocumentElement != null && node.OwnerDocument.DocumentElement.NamespaceURI == nameSpaceURI && | |
| node.OwnerDocument.DocumentElement.Prefix == "")) | |
| { | |
| subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceURI); | |
| } | |
| else | |
| { | |
| subNode = node.OwnerDocument.CreateElement(nodePrefix, nodeName, nameSpaceURI); | |
| } | |
| } | |
| if (prependNode != null) | |
| { | |
| node.InsertBefore(subNode, prependNode); | |
| prependNode = null; | |
| } | |
| else if (insertFirst) | |
| { | |
| node.PrependChild(subNode); | |
| } | |
| else | |
| { | |
| node.AppendChild(subNode); | |
| } | |
| } | |
| } | |
| node = subNode; | |
| } | |
| return node; | |
| } | |
| /// <summary> | |
| /// Options to insert a node in the XmlDocument | |
| /// </summary> | |
| internal enum eNodeInsertOrder | |
| { | |
| /// <summary> | |
| /// Insert as first node of "topNode" | |
| /// </summary> | |
| First, | |
| /// <summary> | |
| /// Insert as the last child of "topNode" | |
| /// </summary> | |
| Last, | |
| /// <summary> | |
| /// Insert after the "referenceNode" | |
| /// </summary> | |
| After, | |
| /// <summary> | |
| /// Insert before the "referenceNode" | |
| /// </summary> | |
| Before, | |
| /// <summary> | |
| /// Use the Schema List to insert in the right order. If the Schema list | |
| /// is null or empty, consider "Last" as the selected option | |
| /// </summary> | |
| SchemaOrder | |
| } | |
| /// <summary> | |
| /// Create a complex node. Insert the node according to SchemaOrder | |
| /// using the TopNode as the parent | |
| /// </summary> | |
| /// <param name="path"></param> | |
| /// <returns></returns> | |
| internal XmlNode CreateComplexNode( | |
| string path) | |
| { | |
| return CreateComplexNode( | |
| TopNode, | |
| path, | |
| eNodeInsertOrder.SchemaOrder, | |
| null); | |
| } | |
| /// <summary> | |
| /// Create a complex node. Insert the node according to the <paramref name="path"/> | |
| /// using the <paramref name="topNode"/> as the parent | |
| /// </summary> | |
| /// <param name="topNode"></param> | |
| /// <param name="path"></param> | |
| /// <returns></returns> | |
| internal XmlNode CreateComplexNode( | |
| XmlNode topNode, | |
| string path) | |
| { | |
| return CreateComplexNode( | |
| topNode, | |
| path, | |
| eNodeInsertOrder.SchemaOrder, | |
| null); | |
| } | |
| /// <summary> | |
| /// Creates complex XML nodes | |
| /// </summary> | |
| /// <remarks> | |
| /// 1. "d:conditionalFormatting" | |
| /// 1.1. Creates/find the first "conditionalFormatting" node | |
| /// | |
| /// 2. "d:conditionalFormatting/@sqref" | |
| /// 2.1. Creates/find the first "conditionalFormatting" node | |
| /// 2.2. Creates (if not exists) the @sqref attribute | |
| /// | |
| /// 3. "d:conditionalFormatting/@id='7'/@sqref='A9:B99'" | |
| /// 3.1. Creates/find the first "conditionalFormatting" node | |
| /// 3.2. Creates/update its @id attribute to "7" | |
| /// 3.3. Creates/update its @sqref attribute to "A9:B99" | |
| /// | |
| /// 4. "d:conditionalFormatting[@id='7']/@sqref='X1:X5'" | |
| /// 4.1. Creates/find the first "conditionalFormatting" node with @id=7 | |
| /// 4.2. Creates/update its @sqref attribute to "X1:X5" | |
| /// | |
| /// 5. "d:conditionalFormatting[@id='7']/@id='8'/@sqref='X1:X5'/d:cfRule/@id='AB'" | |
| /// 5.1. Creates/find the first "conditionalFormatting" node with @id=7 | |
| /// 5.2. Set its @id attribute to "8" | |
| /// 5.2. Creates/update its @sqref attribute and set it to "X1:X5" | |
| /// 5.3. Creates/find the first "cfRule" node (inside the node) | |
| /// 5.4. Creates/update its @id attribute to "AB" | |
| /// | |
| /// 6. "d:cfRule/@id=''" | |
| /// 6.1. Creates/find the first "cfRule" node | |
| /// 6.1. Remove the @id attribute | |
| /// </remarks> | |
| /// <param name="topNode"></param> | |
| /// <param name="path"></param> | |
| /// <param name="nodeInsertOrder"></param> | |
| /// <param name="referenceNode"></param> | |
| /// <returns>The last node creates/found</returns> | |
| internal XmlNode CreateComplexNode( | |
| XmlNode topNode, | |
| string path, | |
| eNodeInsertOrder nodeInsertOrder, | |
| XmlNode referenceNode) | |
| { | |
| // Path is obrigatory | |
| if ((path == null) || (path == string.Empty)) | |
| { | |
| return topNode; | |
| } | |
| XmlNode node = topNode; | |
| string nameSpaceURI = string.Empty; | |
| //TODO: BUG: when the "path" contains "/" in an attrribue value, it gives an error. | |
| // Separate the XPath to Nodes and Attributes | |
| foreach (string subPath in path.Split('/')) | |
| { | |
| // The subPath can be any one of those: | |
| // nodeName | |
| // x:nodeName | |
| // nodeName[find criteria] | |
| // x:nodeName[find criteria] | |
| // @attribute | |
| // @attribute='attribute value' | |
| // Check if the subPath has at least one character | |
| if (subPath.Length > 0) | |
| { | |
| // Check if the subPath is an attribute (with or without value) | |
| if (subPath.StartsWith("@")) | |
| { | |
| // @attribute --> Create attribute | |
| // @attribute='' --> Remove attribute | |
| // @attribute='attribute value' --> Create attribute + update value | |
| string[] attributeSplit = subPath.Split('='); | |
| string attributeName = attributeSplit[0].Substring(1, attributeSplit[0].Length - 1); | |
| string attributeValue = null; // Null means no attribute value | |
| // Check if we have an attribute value to set | |
| if (attributeSplit.Length > 1) | |
| { | |
| // Remove the ' or " from the attribute value | |
| attributeValue = attributeSplit[1].Replace("'", "").Replace("\"", ""); | |
| } | |
| // Get the attribute (if exists) | |
| XmlAttribute attribute = (XmlAttribute)(node.Attributes.GetNamedItem(attributeName)); | |
| // Remove the attribute if value is empty (not null) | |
| if (attributeValue == string.Empty) | |
| { | |
| // Only if the attribute exists | |
| if (attribute != null) | |
| { | |
| node.Attributes.Remove(attribute); | |
| } | |
| } | |
| else | |
| { | |
| // Create the attribue if does not exists | |
| if (attribute == null) | |
| { | |
| // Create the attribute | |
| attribute = node.OwnerDocument.CreateAttribute( | |
| attributeName); | |
| // Add it to the current node | |
| node.Attributes.Append(attribute); | |
| } | |
| // Update the attribute value | |
| if (attributeValue != null) | |
| { | |
| node.Attributes[attributeName].Value = attributeValue; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| // nodeName | |
| // x:nodeName | |
| // nodeName[find criteria] | |
| // x:nodeName[find criteria] | |
| // Look for the node (with or without filter criteria) | |
| XmlNode subNode = node.SelectSingleNode(subPath, NameSpaceManager); | |
| // Check if the node does not exists | |
| if (subNode == null) | |
| { | |
| string nodeName; | |
| string nodePrefix; | |
| string[] nameSplit = subPath.Split(':'); | |
| nameSpaceURI = string.Empty; | |
| // Check if the name has a prefix like "d:nodeName" | |
| if (nameSplit.Length > 1) | |
| { | |
| nodePrefix = nameSplit[0]; | |
| nameSpaceURI = NameSpaceManager.LookupNamespace(nodePrefix); | |
| nodeName = nameSplit[1]; | |
| } | |
| else | |
| { | |
| nodePrefix = string.Empty; | |
| nameSpaceURI = string.Empty; | |
| nodeName = nameSplit[0]; | |
| } | |
| // Check if we have a criteria part in the node name | |
| if (nodeName.IndexOf("[") > 0) | |
| { | |
| // remove the criteria from the node name | |
| nodeName = nodeName.Substring(0, nodeName.IndexOf("[")); | |
| } | |
| if (nodePrefix == string.Empty) | |
| { | |
| subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceURI); | |
| } | |
| else | |
| { | |
| if (node.OwnerDocument != null | |
| && node.OwnerDocument.DocumentElement != null | |
| && node.OwnerDocument.DocumentElement.NamespaceURI == nameSpaceURI | |
| && node.OwnerDocument.DocumentElement.Prefix == string.Empty) | |
| { | |
| subNode = node.OwnerDocument.CreateElement( | |
| nodeName, | |
| nameSpaceURI); | |
| } | |
| else | |
| { | |
| subNode = node.OwnerDocument.CreateElement( | |
| nodePrefix, | |
| nodeName, | |
| nameSpaceURI); | |
| } | |
| } | |
| // Check if we need to use the "SchemaOrder" | |
| if (nodeInsertOrder == eNodeInsertOrder.SchemaOrder) | |
| { | |
| // Check if the Schema Order List is empty | |
| if ((SchemaNodeOrder == null) || (SchemaNodeOrder.Length == 0)) | |
| { | |
| // Use the "Insert Last" option when Schema Order List is empty | |
| nodeInsertOrder = eNodeInsertOrder.Last; | |
| } | |
| else | |
| { | |
| // Find the prepend node in order to insert | |
| referenceNode = GetPrependNode(nodeName, node); | |
| if (referenceNode != null) | |
| { | |
| nodeInsertOrder = eNodeInsertOrder.Before; | |
| } | |
| else | |
| { | |
| nodeInsertOrder = eNodeInsertOrder.Last; | |
| } | |
| } | |
| } | |
| switch (nodeInsertOrder) | |
| { | |
| case eNodeInsertOrder.After: | |
| node.InsertAfter(subNode, referenceNode); | |
| referenceNode = null; | |
| break; | |
| case eNodeInsertOrder.Before: | |
| node.InsertBefore(subNode, referenceNode); | |
| referenceNode = null; | |
| break; | |
| case eNodeInsertOrder.First: | |
| node.PrependChild(subNode); | |
| break; | |
| case eNodeInsertOrder.Last: | |
| node.AppendChild(subNode); | |
| break; | |
| } | |
| } | |
| // Make the newly created node the top node when the rest of the path | |
| // is being evaluated. So newly created nodes will be the children of the | |
| // one we just created. | |
| node = subNode; | |
| } | |
| } | |
| } | |
| // Return the last created/found node | |
| return node; | |
| } | |
| /// <summary> | |
| /// return Prepend node | |
| /// </summary> | |
| /// <param name="nodeName">name of the node to check</param> | |
| /// <param name="node">Topnode to check children</param> | |
| /// <returns></returns> | |
| private XmlNode GetPrependNode(string nodeName, XmlNode node) | |
| { | |
| int pos = GetNodePos(nodeName); | |
| if (pos < 0) | |
| { | |
| return null; | |
| } | |
| XmlNode prependNode = null; | |
| foreach (XmlNode childNode in node.ChildNodes) | |
| { | |
| int childPos = GetNodePos(childNode.Name); | |
| if (childPos > -1) //Found? | |
| { | |
| if (childPos > pos) //Position is before | |
| { | |
| prependNode = childNode; | |
| break; | |
| } | |
| } | |
| } | |
| return prependNode; | |
| } | |
| private int GetNodePos(string nodeName) | |
| { | |
| int ix = nodeName.IndexOf(":"); | |
| if (ix > 0) | |
| { | |
| nodeName = nodeName.Substring(ix + 1, nodeName.Length - (ix + 1)); | |
| } | |
| for (int i = 0; i < _schemaNodeOrder.Length; i++) | |
| { | |
| if (nodeName == _schemaNodeOrder[i]) | |
| { | |
| return i; | |
| } | |
| } | |
| return -1; | |
| } | |
| internal void DeleteAllNode(string path) | |
| { | |
| string[] split = path.Split('/'); | |
| XmlNode node = TopNode; | |
| foreach (string s in split) | |
| { | |
| node = node.SelectSingleNode(s, NameSpaceManager); | |
| if (node != null) | |
| { | |
| if (node is XmlAttribute) | |
| { | |
| (node as XmlAttribute).OwnerElement.Attributes.Remove(node as XmlAttribute); | |
| } | |
| else | |
| { | |
| node.ParentNode.RemoveChild(node); | |
| } | |
| } | |
| else | |
| { | |
| break; | |
| } | |
| } | |
| } | |
| internal void DeleteNode(string path) | |
| { | |
| var node = TopNode.SelectSingleNode(path, NameSpaceManager); | |
| if (node != null) | |
| { | |
| if (node is XmlAttribute) | |
| { | |
| var att = (XmlAttribute)node; | |
| att.OwnerElement.Attributes.Remove(att); | |
| } | |
| else | |
| { | |
| node.ParentNode.RemoveChild(node); | |
| } | |
| } | |
| } | |
| internal void DeleteTopNode() | |
| { | |
| TopNode.ParentNode.RemoveChild(TopNode); | |
| } | |
| internal void SetXmlNodeString(string path, string value) | |
| { | |
| SetXmlNodeString(TopNode, path, value, false, false); | |
| } | |
| internal void SetXmlNodeString(string path, string value, bool removeIfBlank) | |
| { | |
| SetXmlNodeString(TopNode, path, value, removeIfBlank, false); | |
| } | |
| internal void SetXmlNodeString(XmlNode node, string path, string value) | |
| { | |
| SetXmlNodeString(node, path, value, false, false); | |
| } | |
| internal void SetXmlNodeString(XmlNode node, string path, string value, bool removeIfBlank) | |
| { | |
| SetXmlNodeString(node, path, value, removeIfBlank, false); | |
| } | |
| internal void SetXmlNodeString(XmlNode node, string path, string value, bool removeIfBlank, bool insertFirst) | |
| { | |
| if (node == null) | |
| { | |
| return; | |
| } | |
| if (value == "" && removeIfBlank) | |
| { | |
| DeleteAllNode(path); | |
| } | |
| else | |
| { | |
| XmlNode nameNode = node.SelectSingleNode(path, NameSpaceManager); | |
| if (nameNode == null) | |
| { | |
| CreateNode(path, insertFirst); | |
| nameNode = node.SelectSingleNode(path, NameSpaceManager); | |
| } | |
| //if (nameNode.InnerText != value) HasChanged(); | |
| nameNode.InnerText = value; | |
| } | |
| } | |
| internal void SetXmlNodeBool(string path, bool value) | |
| { | |
| SetXmlNodeString(TopNode, path, value ? "1" : "0", false, false); | |
| } | |
| internal void SetXmlNodeBool(string path, bool value, bool removeIf) | |
| { | |
| if (value == removeIf) | |
| { | |
| var node = TopNode.SelectSingleNode(path, NameSpaceManager); | |
| if (node != null) | |
| { | |
| if (node is XmlAttribute) | |
| { | |
| var elem = (node as XmlAttribute).OwnerElement; | |
| elem.ParentNode.RemoveChild(elem); | |
| } | |
| else | |
| { | |
| TopNode.RemoveChild(node); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| SetXmlNodeString(TopNode, path, value ? "1" : "0", false, false); | |
| } | |
| } | |
| internal bool ExistNode(string path) | |
| { | |
| if (TopNode == null || TopNode.SelectSingleNode(path, NameSpaceManager) == null) | |
| { | |
| return false; | |
| } | |
| else | |
| { | |
| return true; | |
| } | |
| } | |
| internal bool? GetXmlNodeBoolNullable(string path) | |
| { | |
| var value = GetXmlNodeString(path); | |
| if (string.IsNullOrEmpty(value)) | |
| { | |
| return null; | |
| } | |
| return GetXmlNodeBool(path); | |
| } | |
| internal bool GetXmlNodeBool(string path) | |
| { | |
| return GetXmlNodeBool(path, false); | |
| } | |
| internal bool GetXmlNodeBool(string path, bool blankValue) | |
| { | |
| string value = GetXmlNodeString(path); | |
| if (value == "1" || value == "-1" || value.Equals("true",StringComparison.InvariantCultureIgnoreCase)) | |
| { | |
| return true; | |
| } | |
| else if (value == "") | |
| { | |
| return blankValue; | |
| } | |
| else | |
| { | |
| return false; | |
| } | |
| } | |
| internal int GetXmlNodeInt(string path) | |
| { | |
| int i; | |
| if (int.TryParse(GetXmlNodeString(path), out i)) | |
| { | |
| return i; | |
| } | |
| else | |
| { | |
| return int.MinValue; | |
| } | |
| } | |
| internal int? GetXmlNodeIntNull(string path) | |
| { | |
| int i; | |
| string s = GetXmlNodeString(path); | |
| if (s!="" && int.TryParse(s, out i)) | |
| { | |
| return i; | |
| } | |
| else | |
| { | |
| return null; | |
| } | |
| } | |
| internal decimal GetXmlNodeDecimal(string path) | |
| { | |
| decimal d; | |
| if (decimal.TryParse(GetXmlNodeString(path), NumberStyles.Any, CultureInfo.InvariantCulture, out d)) | |
| { | |
| return d; | |
| } | |
| else | |
| { | |
| return 0; | |
| } | |
| } | |
| internal decimal? GetXmlNodeDecimalNull(string path) | |
| { | |
| decimal d; | |
| if (decimal.TryParse(GetXmlNodeString(path), NumberStyles.Any, CultureInfo.InvariantCulture, out d)) | |
| { | |
| return d; | |
| } | |
| else | |
| { | |
| return null; | |
| } | |
| } | |
| internal double? GetXmlNodeDoubleNull(string path) | |
| { | |
| string s = GetXmlNodeString(path); | |
| if (s == "") | |
| { | |
| return null; | |
| } | |
| else | |
| { | |
| double v; | |
| if (double.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out v)) | |
| { | |
| return v; | |
| } | |
| else | |
| { | |
| return null; | |
| } | |
| } | |
| } | |
| internal double GetXmlNodeDouble(string path) | |
| { | |
| string s = GetXmlNodeString(path); | |
| if (s == "") | |
| { | |
| return double.NaN; | |
| } | |
| else | |
| { | |
| double v; | |
| if (double.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out v)) | |
| { | |
| return v; | |
| } | |
| else | |
| { | |
| return double.NaN; | |
| } | |
| } | |
| } | |
| internal string GetXmlNodeString(XmlNode node, string path) | |
| { | |
| if (node == null) | |
| { | |
| return ""; | |
| } | |
| XmlNode nameNode = node.SelectSingleNode(path, NameSpaceManager); | |
| if (nameNode != null) | |
| { | |
| if (nameNode.NodeType == XmlNodeType.Attribute) | |
| { | |
| return nameNode.Value != null ? nameNode.Value : ""; | |
| } | |
| else | |
| { | |
| return nameNode.InnerText; | |
| } | |
| } | |
| else | |
| { | |
| return ""; | |
| } | |
| } | |
| internal string GetXmlNodeString(string path) | |
| { | |
| return GetXmlNodeString(TopNode, path); | |
| } | |
| internal static Uri GetNewUri(Packaging.ZipPackage package, string sUri) | |
| { | |
| return GetNewUri(package, sUri, 1); | |
| } | |
| internal static Uri GetNewUri(Packaging.ZipPackage package, string sUri, int id) | |
| { | |
| Uri uri; | |
| do | |
| { | |
| uri = new Uri(string.Format(sUri, id++), UriKind.Relative); | |
| } | |
| while (package.PartExists(uri)); | |
| return uri; | |
| } | |
| /// <summary> | |
| /// Insert the new node before any of the nodes in the comma separeted list | |
| /// </summary> | |
| /// <param name="parentNode">Parent node</param> | |
| /// <param name="beforeNodes">comma separated list containing nodes to insert after. Left to right order</param> | |
| /// <param name="newNode">The new node to be inserterd</param> | |
| internal void InserAfter(XmlNode parentNode, string beforeNodes, XmlNode newNode) | |
| { | |
| string[] nodePaths = beforeNodes.Split(','); | |
| foreach (string nodePath in nodePaths) | |
| { | |
| XmlNode node = parentNode.SelectSingleNode(nodePath, NameSpaceManager); | |
| if (node != null) | |
| { | |
| parentNode.InsertAfter(newNode, node); | |
| return; | |
| } | |
| } | |
| parentNode.InsertAfter(newNode, null); | |
| } | |
| internal static void LoadXmlSafe(XmlDocument xmlDoc, Stream stream) | |
| { | |
| XmlReaderSettings settings = new XmlReaderSettings(); | |
| //Disable entity parsing (to aviod xmlbombs, External Entity Attacks etc). | |
| settings.ProhibitDtd = true; | |
| XmlReader reader = XmlReader.Create(stream, settings); | |
| xmlDoc.Load(reader); | |
| } | |
| internal static void LoadXmlSafe(XmlDocument xmlDoc, string xml, Encoding encoding) | |
| { | |
| var stream = new MemoryStream(encoding.GetBytes(xml)); | |
| LoadXmlSafe(xmlDoc, stream); | |
| } | |
| } | |
| } |