public void GetDigestMethod() { #if NET452 var expected = "http://www.w3.org/2000/09/xmldsig#sha1"; #endif #if NET471 var expected = "http://www.w3.org/2001/04/xmlenc#sha256"; #endif Assert.AreEqual(expected, XmlReference.GetDigestMethod()); }
/// <summary> /// Load the selected XML file and its associated custom file. /// </summary> /// <param name="strFileName">Name of the XML file to load.</param> public XmlDocument Load(string strFileName) { string strPath = Path.Combine(Environment.CurrentDirectory, "data", strFileName); DateTime datDate = File.GetLastWriteTime(strPath); // Look to see if this XmlDocument is already loaded. bool blnFound = false; XmlReference objReference = new XmlReference(); foreach (XmlReference objCurrentReference in _lstXmlDocuments) { if (objCurrentReference.FileName == strFileName) { objReference = objCurrentReference; blnFound = true; break; } } bool blnLoadFile = false; if (!blnFound) { // The file was not found in the reference list, so it must be loaded. blnLoadFile = true; _lstXmlDocuments.Add(objReference); } else { // The file was found in the List, so check the last write time. if (datDate != objReference.FileDate) { // The last write time does not match, so it must be reloaded. blnLoadFile = true; } } // Create a new document that everything will be merged into. XmlDocument objDoc = new XmlDocument(); // write the root chummer node. XmlNode objCont = objDoc.CreateElement("chummer"); objDoc.AppendChild(objCont); XmlDocument objXmlFile = new XmlDocument(); XmlNodeList objList; if (blnLoadFile) { // Load the base file and retrieve all of the child nodes. objXmlFile.Load(strPath); objList = objXmlFile.SelectNodes("/chummer/*"); foreach (XmlNode objNode in objList) { // Append the entire child node to the new document. XmlNode objImported = objDoc.ImportNode(objNode, true); objDoc.DocumentElement.AppendChild(objImported); } // Load any override data files the user might have. Do not attempt this if we're loading the Improvements file. if (strFileName != "improvements.xml") { string strFilePath = Path.Combine(Environment.CurrentDirectory, "data"); foreach (string strFile in Directory.GetFiles(strFilePath, "override*_" + strFileName)) { objXmlFile.Load(strFile); objList = objXmlFile.SelectNodes("/chummer/*"); foreach (XmlNode objNode in objList) { foreach (XmlNode objType in objNode.ChildNodes) { if (objType["id"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objNode.Name + "/" + objType.Name + "[id = \"" + objType["id"].InnerText.Replace("&", "&") + "\"]"); if (objItem != null) objItem.InnerXml = objType.InnerXml; } else if (objType["name"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objNode.Name + "/" + objType.Name + "[name = \"" + objType["name"].InnerText.Replace("&", "&") + "\"]"); if (objItem != null) objItem.InnerXml = objType.InnerXml; } } } } } // Load the translation file for the current base data file if the selected language is not en-us. if (GlobalOptions.Instance.Language != "en-us") { // Everything is stored in the selected language file to make translations easier, keep all of the language-specific information together, and not require users to download 27 individual files. // The structure is similar to the base data file, but the root node is instead a child /chummer node with a file attribute to indicate the XML file it translates. if (LanguageManager.Instance.DataDoc != null) { foreach (XmlNode objNode in LanguageManager.Instance.DataDoc.SelectNodes("/chummer/chummer[@file = \"" + strFileName + "\"]")) { foreach (XmlNode objType in objNode.ChildNodes) { foreach (XmlNode objChild in objType.ChildNodes) { // If this is a translatable item, find the proper node and add/update this information. if (objChild["translate"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/" + objChild.Name + "[name = \"" + objChild["name"].InnerXml.Replace("&", "&") + "\"]"); if (objItem != null) objItem.InnerXml += "<translate>" + objChild["translate"].InnerXml + "</translate>"; } if (objChild["page"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/" + objChild.Name + "[name = \"" + objChild["name"].InnerXml.Replace("&", "&") + "\"]"); if (objItem != null) objItem.InnerXml += "<altpage>" + objChild["page"].InnerXml + "</altpage>"; } if (objChild["code"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/" + objChild.Name + "[name = \"" + objChild["name"].InnerXml.Replace("&", "&") + "\"]"); if (objItem != null) objItem.InnerXml += "<altcode>" + objChild["code"].InnerXml + "</altcode>"; } if (objChild["advantage"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/" + objChild.Name + "[name = \"" + objChild["name"].InnerXml.Replace("&", "&") + "\"]"); if (objItem != null) objItem.InnerXml += "<altadvantage>" + objChild["advantage"].InnerXml + "</altadvantage>"; } if (objChild["disadvantage"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/" + objChild.Name + "[name = \"" + objChild["name"].InnerXml.Replace("&", "&") + "\"]"); if (objItem != null) objItem.InnerXml += "<altdisadvantage>" + objChild["disadvantage"].InnerXml + "</altdisadvantage>"; } if (objChild.Attributes != null) { // Handle Category name translations. if (objChild.Attributes["translate"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/" + objChild.Name + "[. = \"" + objChild.InnerXml.Replace("&", "&") + "\"]"); if (objItem != null) { XmlElement objElement = (XmlElement)objItem; objElement.SetAttribute("translate", objChild.Attributes["translate"].InnerXml); } } } // Check for Skill Specialization information. if (strFileName == "skills.xml") { if (objChild["specs"] != null) { foreach (XmlNode objSpec in objChild.SelectNodes("specs/spec")) { if (objSpec.Attributes["translate"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/skill[name = \"" + objChild["name"].InnerXml + "\"]/specs/spec[. = \"" + objSpec.InnerXml + "\"]"); if (objItem != null) { XmlElement objElement = (XmlElement)objItem; objElement.SetAttribute("translate", objSpec.Attributes["translate"].InnerXml); } } } } } // Check for Metavariant information. if (strFileName == "metatypes.xml") { if (objChild["metavariants"] != null) { foreach (XmlNode objMetavariant in objChild.SelectNodes("metavariants/metavariant")) { if (objMetavariant["translate"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/metatypes/metatype[name = \"" + objChild["name"].InnerXml + "\"]/metavariants/metavariant[name = \"" + objMetavariant["name"].InnerXml + "\"]"); if (objItem != null) objItem.InnerXml += "<translate>" + objMetavariant["translate"].InnerXml + "</translate>"; } if (objMetavariant["altpage"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/metatypes/metatype[name = \"" + objChild["name"].InnerXml + "\"]/metavariants/metavariant[name = \"" + objMetavariant["name"].InnerXml + "\"]"); if (objItem != null) objItem.InnerXml += "<altpage>" + objMetavariant["page"].InnerXml + "</altpage>"; } } } } // Check for Martial Art Advantage information. if (strFileName == "martialarts.xml") { if (objChild["advantages"] != null) { foreach (XmlNode objAdvantage in objChild.SelectNodes("techniques/technique")) { if (objAdvantage.Attributes["translate"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/martialarts/martialart[name = \"" + objChild["name"].InnerXml + "\"]/techniques/technique[. = \"" + objAdvantage.InnerXml + "\"]"); if (objItem != null) { XmlElement objElement = (XmlElement)objItem; objElement.SetAttribute("translate", objAdvantage.Attributes["translate"].InnerXml); } } } } } // Check for Mentor Spirit/Paragon choice information. if (strFileName == "mentors.xml" || strFileName == "paragons.xml") { if (objChild["choices"] != null) { foreach (XmlNode objChoice in objChild.SelectNodes("choices/choice")) { if (objChoice["translate"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/mentors/mentor[name = \"" + objChild["name"].InnerXml + "\"]/choices/choice[name = \"" + objChoice["name"].InnerXml + "\"]"); if (objItem != null) objItem.InnerXml += "<translate>" + objChoice["translate"].InnerXml + "</translate>"; } } } } } } } } } // Cache the merged document and its relevant information. objReference.FileDate = datDate; objReference.FileName = strFileName; objReference.XmlContent = objDoc; } else { // Pull the document from cache. objDoc = objReference.XmlContent; } // A new XmlDocument is created by loading the a copy of the cached one so that we don't stuff custom content into the cached copy // (which we don't want and also results in multiple copies of each custom item). XmlDocument objReturnDocument = new XmlDocument(); objReturnDocument.LoadXml(objDoc.OuterXml); // Load any custom data files the user might have. Do not attempt this if we're loading the Improvements file. if (strFileName != "improvements.xml") { strPath = Path.Combine(Environment.CurrentDirectory, "data"); foreach (string strFile in Directory.GetFiles(strPath, "custom*_" + strFileName)) { objXmlFile.Load(strFile); objList = objXmlFile.SelectNodes("/chummer/*"); foreach (XmlNode objNode in objList) { // Look for any items with a duplicate name and pluck them from the node so we don't end up with multiple items with the same name. List<XmlNode> lstDelete = new List<XmlNode>(); foreach (XmlNode objChild in objNode.ChildNodes) { // Only do this if the child has the name field since this is what we must match on. if (objChild["name"] != null) { XmlNodeList objNodeList = objReturnDocument.SelectNodes("/chummer/" + objChild.ParentNode.Name + "/" + objChild.Name + "[name = \"" + objChild["name"].InnerText + "\"]"); if (objNodeList.Count > 0) { lstDelete.Add(objChild); } } } // Remove the offending items from the node we're about to merge in. foreach (XmlNode objRemoveNode in lstDelete) { objNode.RemoveChild(objRemoveNode); } // Append the entire child node to the new document. XmlNode objImported = objReturnDocument.ImportNode(objNode, true); objReturnDocument.DocumentElement.AppendChild(objImported); } } } return objReturnDocument; }
/// <summary> /// Load the selected XML file and its associated custom file. /// </summary> /// <param name="strFileName">Name of the XML file to load.</param> public XmlDocument Load(string strFileName) { string strPath = Path.Combine(Environment.CurrentDirectory, "data", strFileName); DateTime datDate = File.GetLastWriteTime(strPath); // Look to see if this XmlDocument is already loaded. bool blnFound = false; XmlReference objReference = new XmlReference(); foreach (XmlReference objCurrentReference in _lstXmlDocuments) { if (objCurrentReference.FileName == strFileName) { objReference = objCurrentReference; blnFound = true; break; } } bool blnLoadFile = false; if (!blnFound) { // The file was not found in the reference list, so it must be loaded. blnLoadFile = true; _lstXmlDocuments.Add(objReference); } else { // The file was found in the List, so check the last write time. if (datDate != objReference.FileDate) { // The last write time does not match, so it must be reloaded. blnLoadFile = true; } } // Create a new document that everything will be merged into. XmlDocument objDoc = new XmlDocument(); // write the root chummer node. XmlNode objCont = objDoc.CreateElement("chummer"); objDoc.AppendChild(objCont); XmlDocument objXmlFile = new XmlDocument(); XmlNodeList objList; if (blnLoadFile) { // Load the base file and retrieve all of the child nodes. objXmlFile.Load(strPath); objList = objXmlFile.SelectNodes("/chummer/*"); foreach (XmlNode objNode in objList) { // Append the entire child node to the new document. XmlNode objImported = objDoc.ImportNode(objNode, true); objDoc.DocumentElement.AppendChild(objImported); } // Load any override data files the user might have. Do not attempt this if we're loading the Improvements file. if (strFileName != "improvements.xml") { string strFilePath = Path.Combine(Environment.CurrentDirectory, "data"); foreach (string strFile in Directory.GetFiles(strFilePath, "override*_" + strFileName)) { objXmlFile.Load(strFile); objList = objXmlFile.SelectNodes("/chummer/*"); foreach (XmlNode objNode in objList) { foreach (XmlNode objType in objNode.ChildNodes) { if (objType["name"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objNode.Name + "/" + objType.Name + "[name = \"" + objType["name"].InnerText.Replace("&", "&") + "\"]"); if (objItem != null) { objItem.InnerXml = objType.InnerXml; } } } } } } // Load the translation file for the current base data file if the selected language is not en-us. if (GlobalOptions.Instance.Language != "en-us") { // Everything is stored in the selected language file to make translations easier, keep all of the language-specific information together, and not require users to download 27 individual files. // The structure is similar to the base data file, but the root node is instead a child /chummer node with a file attribute to indicate the XML file it translates. if (LanguageManager.Instance.DataDoc != null) { foreach (XmlNode objNode in LanguageManager.Instance.DataDoc.SelectNodes("/chummer/chummer[@file = \"" + strFileName + "\"]")) { foreach (XmlNode objType in objNode.ChildNodes) { foreach (XmlNode objChild in objType.ChildNodes) { // If this is a translatable item, find the proper node and add/update this information. if (objChild["translate"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/" + objChild.Name + "[name = \"" + objChild["name"].InnerXml.Replace("&", "&") + "\"]"); if (objItem != null) { objItem.InnerXml += "<translate>" + objChild["translate"].InnerXml + "</translate>"; } } if (objChild["page"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/" + objChild.Name + "[name = \"" + objChild["name"].InnerXml.Replace("&", "&") + "\"]"); if (objItem != null) { objItem.InnerXml += "<altpage>" + objChild["page"].InnerXml + "</altpage>"; } } if (objChild["code"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/" + objChild.Name + "[name = \"" + objChild["name"].InnerXml.Replace("&", "&") + "\"]"); if (objItem != null) { objItem.InnerXml += "<altcode>" + objChild["code"].InnerXml + "</altcode>"; } } if (objChild["advantage"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/" + objChild.Name + "[name = \"" + objChild["name"].InnerXml.Replace("&", "&") + "\"]"); if (objItem != null) { objItem.InnerXml += "<altadvantage>" + objChild["advantage"].InnerXml + "</altadvantage>"; } } if (objChild["disadvantage"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/" + objChild.Name + "[name = \"" + objChild["name"].InnerXml.Replace("&", "&") + "\"]"); if (objItem != null) { objItem.InnerXml += "<altdisadvantage>" + objChild["disadvantage"].InnerXml + "</altdisadvantage>"; } } if (objChild.Attributes != null) { // Handle Category name translations. if (objChild.Attributes["translate"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/" + objChild.Name + "[. = \"" + objChild.InnerXml.Replace("&", "&") + "\"]"); if (objItem != null) { XmlElement objElement = (XmlElement)objItem; objElement.SetAttribute("translate", objChild.Attributes["translate"].InnerXml); } } } // Check for Skill Specialization information. if (strFileName == "skills.xml") { if (objChild["specs"] != null) { foreach (XmlNode objSpec in objChild.SelectNodes("specs/spec")) { if (objSpec.Attributes["translate"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/skill[name = \"" + objChild["name"].InnerXml + "\"]/specs/spec[. = \"" + objSpec.InnerXml + "\"]"); if (objItem != null) { XmlElement objElement = (XmlElement)objItem; objElement.SetAttribute("translate", objSpec.Attributes["translate"].InnerXml); } } } } } // Check for Metavariant information. if (strFileName == "metatypes.xml") { if (objChild["metavariants"] != null) { foreach (XmlNode objMetavariant in objChild.SelectNodes("metavariants/metavariant")) { if (objMetavariant["translate"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/metatypes/metatype[name = \"" + objChild["name"].InnerXml + "\"]/metavariants/metavariant[name = \"" + objMetavariant["name"].InnerXml + "\"]"); if (objItem != null) { objItem.InnerXml += "<translate>" + objMetavariant["translate"].InnerXml + "</translate>"; } } if (objMetavariant["altpage"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/metatypes/metatype[name = \"" + objChild["name"].InnerXml + "\"]/metavariants/metavariant[name = \"" + objMetavariant["name"].InnerXml + "\"]"); if (objItem != null) { objItem.InnerXml += "<altpage>" + objMetavariant["page"].InnerXml + "</altpage>"; } } } } } // Check for Martial Art Advantage information. if (strFileName == "martialarts.xml") { if (objChild["advantages"] != null) { foreach (XmlNode objAdvantage in objChild.SelectNodes("techniques/technique")) { if (objAdvantage.Attributes["translate"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/martialarts/martialart[name = \"" + objChild["name"].InnerXml + "\"]/techniques/technique[. = \"" + objAdvantage.InnerXml + "\"]"); if (objItem != null) { XmlElement objElement = (XmlElement)objItem; objElement.SetAttribute("translate", objAdvantage.Attributes["translate"].InnerXml); } } } } } // Check for Mentor Spirit/Paragon choice information. if (strFileName == "mentors.xml" || strFileName == "paragons.xml") { if (objChild["choices"] != null) { foreach (XmlNode objChoice in objChild.SelectNodes("choices/choice")) { if (objChoice["translate"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/mentors/mentor[name = \"" + objChild["name"].InnerXml + "\"]/choices/choice[name = \"" + objChoice["name"].InnerXml + "\"]"); if (objItem != null) { objItem.InnerXml += "<translate>" + objChoice["translate"].InnerXml + "</translate>"; } } } } } } } } } } // Cache the merged document and its relevant information. objReference.FileDate = datDate; objReference.FileName = strFileName; objReference.XmlContent = objDoc; } else { // Pull the document from cache. objDoc = objReference.XmlContent; } // A new XmlDocument is created by loading the a copy of the cached one so that we don't stuff custom content into the cached copy // (which we don't want and also results in multiple copies of each custom item). XmlDocument objReturnDocument = new XmlDocument(); objReturnDocument.LoadXml(objDoc.OuterXml); // Load any custom data files the user might have. Do not attempt this if we're loading the Improvements file. if (strFileName != "improvements.xml") { strPath = Path.Combine(Environment.CurrentDirectory, "data"); foreach (string strFile in Directory.GetFiles(strPath, "custom*_" + strFileName)) { objXmlFile.Load(strFile); objList = objXmlFile.SelectNodes("/chummer/*"); foreach (XmlNode objNode in objList) { // Look for any items with a duplicate name and pluck them from the node so we don't end up with multiple items with the same name. List <XmlNode> lstDelete = new List <XmlNode>(); foreach (XmlNode objChild in objNode.ChildNodes) { // Only do this if the child has the name field since this is what we must match on. if (objChild["name"] != null) { XmlNodeList objNodeList = objReturnDocument.SelectNodes("/chummer/" + objChild.ParentNode.Name + "/" + objChild.Name + "[name = \"" + objChild["name"].InnerText + "\"]"); if (objNodeList.Count > 0) { lstDelete.Add(objChild); } } } // Remove the offending items from the node we're about to merge in. foreach (XmlNode objRemoveNode in lstDelete) { objNode.RemoveChild(objRemoveNode); } // Append the entire child node to the new document. XmlNode objImported = objReturnDocument.ImportNode(objNode, true); objReturnDocument.DocumentElement.AppendChild(objImported); } } } return(objReturnDocument); }
/// <summary> /// Load the selected XML file and its associated custom file. /// </summary> /// <param name="strFileName">Name of the XML file to load.</param> /// <param name="blnLoadFile">Whether to force reloading content even if the file already exists.</param> public XmlDocument Load(string strFileName, bool blnLoadFile = false) { string strPath = Path.Combine(Application.StartupPath, "data", strFileName); if (!File.Exists(strPath)) { Utils.BreakIfDebug(); return(null); } DateTime datDate = File.GetLastWriteTime(strPath); // Look to see if this XmlDocument is already loaded. XmlReference objReference = _lstXmlDocuments.Find(x => x.FileName == strFileName); if (objReference == null || blnLoadFile) { // The file was not found in the reference list, so it must be loaded. objReference = new XmlReference(); blnLoadFile = true; _lstXmlDocuments.Add(objReference); } // The file was found in the List, so check the last write time. else if (datDate != objReference.FileDate) { // The last write time does not match, so it must be reloaded. blnLoadFile = true; } // Create a new document that everything will be merged into. XmlDocument objDoc; XmlDocument objXmlFile = new XmlDocument(); if (blnLoadFile) { objDoc = new XmlDocument(); // write the root chummer node. XmlNode objCont = objDoc.CreateElement("chummer"); objDoc.AppendChild(objCont); // Load the base file and retrieve all of the child nodes. objXmlFile.Load(strPath); XmlNodeList xmlNodeList = objXmlFile.SelectNodes("/chummer/*"); if (xmlNodeList != null) { foreach (XmlNode objNode in xmlNodeList) { // Append the entire child node to the new document. objDoc.DocumentElement.AppendChild(objDoc.ImportNode(objNode, true)); } } // Load any override data files the user might have. Do not attempt this if we're loading the Improvements file. if (strFileName != "improvements.xml") { strPath = Path.Combine(Application.StartupPath, "data"); foreach (string strFile in Directory.GetFiles(strPath, "override*_" + strFileName)) { objXmlFile.Load(strFile); foreach (XmlNode objNode in objXmlFile.SelectNodes("/chummer/*")) { foreach (XmlNode objType in objNode.ChildNodes) { if (objType["id"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objNode.Name + "/" + objType.Name + "[id = \"" + objType["id"].InnerText.Replace("&", "&") + "\"]"); if (objItem != null) { objItem.InnerXml = objType.InnerXml; } } else if (objType["name"] != null) { XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objNode.Name + "/" + objType.Name + "[name = \"" + objType["name"].InnerText.Replace("&", "&") + "\"]"); if (objItem != null) { objItem.InnerXml = objType.InnerXml; } } } } } // Load any custom data files the user might have. Do not attempt this if we're loading the Improvements file. foreach (string strFile in Directory.GetFiles(strPath, "custom*_" + strFileName)) { objXmlFile.Load(strFile); foreach (XmlNode objNode in objXmlFile.SelectNodes("/chummer/*")) { // Look for any items with a duplicate name and pluck them from the node so we don't end up with multiple items with the same name. List <XmlNode> lstDelete = new List <XmlNode>(); foreach (XmlNode objChild in objNode.ChildNodes) { if (objChild.ParentNode != null) { // Only do this if the child has the name or id field since this is what we must match on. if (objChild["id"] != null && null != objDoc.SelectSingleNode("/chummer/" + objChild.ParentNode.Name + "/" + objChild.Name + "[name = \"" + objChild["id"].InnerText + "\"]")) { lstDelete.Add(objChild); } else if (objChild["name"] != null && null != objDoc.SelectSingleNode("/chummer/" + objChild.ParentNode.Name + "/" + objChild.Name + "[name = \"" + objChild["name"].InnerText + "\"]")) { lstDelete.Add(objChild); } } } // Remove the offending items from the node we're about to merge in. foreach (XmlNode objRemoveNode in lstDelete) { objNode.RemoveChild(objRemoveNode); } // Append the entire child node to the new document. objDoc.DocumentElement?.AppendChild(objDoc.ImportNode(objNode, true)); } } } // Load the translation file for the current base data file if the selected language is not en-us. if (GlobalOptions.Instance.Language != "en-us") { // Everything is stored in the selected language file to make translations easier, keep all of the language-specific information together, and not require users to download 27 individual files. // The structure is similar to the base data file, but the root node is instead a child /chummer node with a file attribute to indicate the XML file it translates. if (LanguageManager.Instance.DataDoc != null) { foreach (XmlNode objNode in LanguageManager.Instance.DataDoc.SelectNodes("/chummer/chummer[@file = \"" + strFileName + "\"]")) { foreach (XmlNode objType in objNode.ChildNodes) { foreach (XmlNode objChild in objType.ChildNodes) { if (objChild["name"] != null) { // If this is a translatable item, find the proper node and add/update this information. XmlNode objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/" + objChild.Name + "[name = \"" + objChild["name"].InnerXml.Replace("&", "&") + "\"]"); if (objItem != null) { if (objChild["translate"] != null) { objItem.InnerXml += "<translate>" + objChild["translate"].InnerXml + "</translate>"; } if (objChild["page"] != null) { objItem.InnerXml += "<altpage>" + objChild["page"].InnerXml + "</altpage>"; } if (objChild["code"] != null) { objItem.InnerXml += "<altcode>" + objChild["code"].InnerXml + "</altcode>"; } if (objChild["advantage"] != null) { objItem.InnerXml += "<altadvantage>" + objChild["advantage"].InnerXml + "</altadvantage>"; } if (objChild["disadvantage"] != null) { objItem.InnerXml += "<altdisadvantage>" + objChild["disadvantage"].InnerXml + "</altdisadvantage>"; } if (objChild.Attributes?["translate"] != null) { // Handle Category name translations. (objItem as XmlElement)?.SetAttribute("translate", objChild.Attributes["translate"].InnerXml); } // Check for Skill Specialization information. if (strFileName == "skills.xml") { if (objChild["specs"] != null) { foreach (XmlNode objSpec in objChild.SelectNodes("specs/spec")) { if (objSpec.Attributes?["translate"] != null) { XmlElement objSpecItem = objItem.SelectSingleNode("specs/spec[. = \"" + objSpec.InnerXml + "\"]") as XmlElement; objSpecItem?.SetAttribute("translate", objSpec.Attributes["translate"].InnerXml); } } } } // Check for Metavariant information. else if (strFileName == "metatypes.xml") { if (objChild["metavariants"] != null) { foreach (XmlNode objMetavariant in objChild.SelectNodes("metavariants/metavariant")) { if (objMetavariant["name"] != null && objChild["name"] != null) { XmlNode objMetavariantItem = objDoc.SelectSingleNode( "/chummer/metatypes/metatype[name = \"" + objChild["name"].InnerXml + "\"]/metavariants/metavariant[name = \"" + objMetavariant["name"].InnerXml + "\"]"); if (objMetavariantItem != null) { if (objMetavariant["translate"] != null) { objMetavariantItem.InnerXml += "<translate>" + objMetavariant[ "translate"].InnerXml + "</translate>"; } if (objMetavariant["page"] != null) { objMetavariantItem.InnerXml += "<altpage>" + objMetavariant["page"] .InnerXml + "</altpage>"; } } } } } } // Check for Martial Art Advantage information. else if (strFileName == "martialarts.xml") { if (objChild["advantages"] != null) { foreach (XmlNode objAdvantage in objChild.SelectNodes("techniques/technique")) { if (objAdvantage.Attributes?["translate"] != null) { XmlElement objAdvantageItem = objItem.SelectSingleNode("techniques/technique[. = \"" + objAdvantage.InnerXml + "\"]") as XmlElement; objAdvantageItem?.SetAttribute("translate", objAdvantage.Attributes["translate"].InnerXml); } } } } // Check for Mentor Spirit/Paragon choice information. else if (strFileName == "mentors.xml" || strFileName == "paragons.xml") { if (objChild["choices"] != null) { foreach (XmlNode objChoice in objChild.SelectNodes("choices/choice")) { if (objChoice["name"] != null && objChoice["translate"] != null) { XmlNode objChoiceItem = objItem.SelectSingleNode("choices/choice[name = \"" + objChoice["name"].InnerXml + "\"]"); if (objChoiceItem != null) { objChoiceItem.InnerXml += "<translate>" + objChoice["translate"].InnerXml + "</translate>"; } } } } } } } else if (objChild.Attributes?["translate"] != null) { // Handle Category name translations. XmlElement objItem = objDoc.SelectSingleNode("/chummer/" + objType.Name + "/" + objChild.Name + "[. = \"" + objChild.InnerXml.Replace("&", "&") + "\"]") as XmlElement; // Expected result is null if not found. objItem?.SetAttribute("translate", objChild.Attributes["translate"].InnerXml); } } } } } } // Cache the merged document and its relevant information. objReference.FileDate = datDate; objReference.FileName = strFileName; if (GlobalOptions.Instance.LiveCustomData) { objReference.XmlContent = objDoc.Clone() as XmlDocument; } else { objReference.XmlContent = objDoc; } } else { // A new XmlDocument is created by loading the a copy of the cached one so that we don't stuff custom content into the cached copy // (which we don't want and also results in multiple copies of each custom item). // Pull the document from cache. if (GlobalOptions.Instance.LiveCustomData) { objDoc = objReference.XmlContent.Clone() as XmlDocument; } else { objDoc = objReference.XmlContent; } } // Load any custom data files the user might have. Do not attempt this if we're loading the Improvements file. if (GlobalOptions.Instance.LiveCustomData && objDoc != null && strFileName != "improvements.xml") { strPath = Path.Combine(Application.StartupPath, "customdata"); if (Directory.Exists(strPath)) { foreach (string strFile in Directory.GetFiles(strPath, "custom*_" + strFileName)) { objXmlFile.Load(strFile); foreach (XmlNode objNode in objXmlFile.SelectNodes("/chummer/*")) { // Look for any items with a duplicate name and pluck them from the node so we don't end up with multiple items with the same name. List <XmlNode> lstDelete = new List <XmlNode>(); foreach (XmlNode objChild in objNode.ChildNodes) { // Only do this if the child has the name or id field since this is what we must match on. if (objChild["id"] != null && null != objDoc.SelectSingleNode("/chummer/" + objChild.ParentNode.Name + "/" + objChild.Name + "[name = \"" + objChild["id"].InnerText + "\"]")) { lstDelete.Add(objChild); } else if (objChild["name"] != null && null != objDoc.SelectSingleNode("/chummer/" + objChild.ParentNode.Name + "/" + objChild.Name + "[name = \"" + objChild["name"].InnerText + "\"]")) { lstDelete.Add(objChild); } } // Remove the offending items from the node we're about to merge in. foreach (XmlNode objRemoveNode in lstDelete) { objNode.RemoveChild(objRemoveNode); } // Append the entire child node to the new document. objDoc.DocumentElement?.AppendChild(objDoc.ImportNode(objNode, true)); } } } } //Check for non-unique guids in the loaded XML file. Ignore improvements.xml since the ids are used in a different way. if (strFileName == "improvements.xml" || objReference.DuplicatesChecked) { return(objDoc); } { foreach (XmlNode objNode in objDoc.SelectNodes("/chummer/*")) { //Ignore the version node, if present. if (objNode.Name == "version" || !objNode.HasChildNodes) { continue; } //Parse the node into an XDocument for LINQ parsing. XDocument y = XDocument.Parse(objNode.OuterXml); string strNode = (from XmlNode o in objNode.ChildNodes where o.NodeType != XmlNodeType.Comment select o.Name).FirstOrDefault(); //Grab the first XML node that isn't a comment. if (strNode == null) { continue; } var duplicatesList = y.Descendants(strNode) .GroupBy(g => (string)g.Element("id") ?? "") .Where(g => g.Count() > 1) .Select(g => g.Key) .ToList(); int i = duplicatesList.Count(o => !string.IsNullOrWhiteSpace(o)); if (i <= 0) { objReference.DuplicatesChecked = true; continue; } string duplicates = string.Join("\n", duplicatesList); MessageBox.Show( LanguageManager.Instance.GetString("Message_DuplicateGuidWarning") .Replace("{0}", i.ToString()) .Replace("{1}", strFileName) .Replace("{2}", duplicates)); } } return(objDoc); }