/// <summary> /// Convert form fields pointing to a system property from an ID reference to a search /// </summary> private void FixFormFieldsPointingToSystemProperties(XmlDocument doc) { const string sysProps = "|behavior|classification|config_id|created_by_id|created_on|css|current_state|generation|history_id|id|is_current|is_released|keyed_name|release_date|effective_date|locked_by_id|major_rev|managed_by_id|minor_rev|modified_by_id|modified_on|new_version|not_lockable|owned_by_id|permission_id|related_id|sort_order|source_id|state|itemtype|superseded_date|team_id|"; var fields = doc.ElementsByXPath("//Item[@type='Field'][contains($p0,concat('|',propertytype_id/@keyed_name,'|'))]", sysProps).ToList(); if (fields.Count < 1) return; var query = "<Item type=\"Property\" action=\"get\" idlist=\"" + fields.GroupConcat(",", f => f.Element("propertytype_id", "")) + "\" select=\"name,source_id\" />"; // Get all the property information from the database var results = _conn.Apply(query).Items().ToDictionary(e => e.Id(), e => new Command( @"<Item type='@0' action='get' select='id'> <name>@1</name> <source_id>@2</source_id> </Item>", e.Type().Value, e.Property("name").Value, e.SourceId().Value) .ToNormalizedAml(_conn.AmlContext.LocalizationContext)); // Update the export the the proper edit scripts string propData; XmlDocument tempDoc; XmlElement propType; XmlElement parentItem; XmlElement script; foreach (var field in fields) { if (results.TryGetValue(field.Element("propertytype_id", ""), out propData)) { propType = field.Element("propertytype_id"); propType.RemoveAll(); tempDoc = doc.NewDoc(); tempDoc.LoadXml(propData); propType.AppendChild(propType.OwnerDocument.ImportNode(tempDoc.DocumentElement, true)); propType.Detatch(); parentItem = field.Parents().Last(e => e.LocalName == "Item"); script = parentItem.OwnerDocument.CreateElement("Item") .Attr("type", field.Attribute("type")) .Attr("id", field.Attribute("id")) .Attr("action", "edit") .Attr(XmlFlags.Attr_ScriptType, "6"); script.AppendChild(propType); parentItem.Parent().InsertAfter(script, parentItem); } } }
/// <summary> /// Transform the results to normalize the output using the XSLT /// </summary> private XmlDocument TransformResults(ref XmlDocument results) { EnsureTransforms(); var doc = results.NewDoc(); // Transform the output ReportProgress(94, "Transforming the results"); using (var memStream = new MemoryStream(results.DocumentElement.ChildNodes.Count * 1000)) using (var output = new StreamWriter(memStream)) { using (var reader = new XmlNodeReader(results.DocumentElement)) { _resultTransform.Transform(reader, null, output); } // Nullify the original document immediately to reclaim the memory ASAP results = null; output.Flush(); memStream.Position = 0; doc.Load(memStream); } // Make sure empty elements truly empty var emptyElements = doc.Descendants(e => !e.HasChildNodes && !e.IsEmpty).ToArray(); foreach (var emptyElem in emptyElements) { emptyElem.IsEmpty = true; } return doc; }
/// <summary> /// Execute the query to get all the relevant data from the database regarding the items to export. /// </summary> private XmlDocument ExecuteExportQuery(ref XmlDocument query, IEnumerable<ItemReference> itemRefs) { var itemDic = itemRefs.ToDictionary(i => i); var queryItems = query.DocumentElement.Elements("Item"); var result = query.NewDoc(); ReportProgress(4, "Searching for data..."); var promises = queryItems.Select(q => (Func<IPromise>)( () => _conn.Process(q, true) .Convert(s => { return (IEnumerable<XmlElement>)(Items(result, s, itemDic).ToArray()); }) ) ).ToArray(); query = null; // Release the query memory as soon as possible; var items = Promises.Pooled(30, promises) .Progress((i, m) => { ReportProgress(4 + (int)(i * 0.9), "Searching for data..."); }).Wait(); ReportProgress(95, "Loading results into memory..."); var elems = items.SelectMany(r => (IEnumerable<XmlElement>)r); var root = result.Elem("Result"); foreach (var elem in elems) { root.AppendChild(elem); } return result; }
/// <summary> /// Normalize the formatting of class structure nodes to aid in manual line-based diff-ing /// </summary> private void NormalizeClassStructure(XmlDocument doc) { ReportProgress(97, "Transforming the results"); var settings = new XmlWriterSettings(); settings.OmitXmlDeclaration = true; settings.Indent = true; settings.IndentChars = " "; var classStructs = (from e in doc.ElementsByXPath("//Item[@type='ItemType']/class_structure") where !string.IsNullOrEmpty(e.InnerText) select e); XmlDocument classDoc; foreach (var classStruct in classStructs) { classDoc = doc.NewDoc(); var text = classStruct.InnerText; classDoc.LoadXml(text); var sb = new StringBuilder((int)(text.Length * 1.4)); using (var output = new StringWriter(sb)) { using (var writer = XmlTextWriter.Create(output, settings)) { WriteClassStruct(Enumerable.Repeat((XmlNode)classDoc.DocumentElement, 1), writer); } classStruct.IsEmpty = true; classStruct.AppendChild(doc.CreateCDataSection(output.ToString())); } } }