/// <summary> /// The Weather list is never used, so delete it (and remove any empty Weather elements /// from the RnGenericRec elements). /// </summary> private void DeleteWeatherListAndField(IDomainObjectDTORepository repoDTO) { // Remove the Weather list. DomainObjectDTO dtoLP = GetDtoLangProj(repoDTO); string sWeatherListGuid = RemoveWeatherConditionsElement(dtoLP).ToLowerInvariant(); repoDTO.Update(dtoLP); DomainObjectDTO dtoDeadList = null; foreach (var dto in repoDTO.AllInstancesWithSubclasses("CmPossibilityList")) { if (dto.Guid.ToLowerInvariant() == sWeatherListGuid) { dtoDeadList = dto; break; } } List<DomainObjectDTO> rgdtoDead = new List<DomainObjectDTO>(); GatherDeadObjects(repoDTO, dtoDeadList, rgdtoDead); foreach (var dto in rgdtoDead) repoDTO.Remove(dto); // Remove any empty Weather elements in the RnGenericRec objects. foreach (var dto in repoDTO.AllInstancesWithSubclasses("RnGenericRec")) { string sXml = dto.Xml; int idx = sXml.IndexOf("<Weather"); if (idx > 0) { dto.Xml = RemoveEmptyWeather(sXml, idx); repoDTO.Update(dto); } } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Change all guids to lowercase to help the Chorus diff/merge code. /// </summary> /// ------------------------------------------------------------------------------------ public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository) { DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000024); const string dateCreated = "DateCreated"; var properties = new List<string> { dateCreated, "DateModified" }; ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("CmProject"), properties); // Tested ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("CmMajorObject"), properties); // Tested ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("CmPossibility"), properties); // Tested ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("CmAnnotation"), properties); // Tested ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("StJournalText"), properties); // Tested ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("LexEntry"), properties); // Tested ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("RnGenericRec"), properties); // Tested // Since ScrScriptureNote derives from CmBaseAnnotation, which has already had it DateCreated & DateModified updated, // we have to clear those two out of the dictioanry, or they will be updated twice, and the test on ScrScriptureNote will fail. properties.Clear(); properties.Add("DateResolved"); ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("ScrScriptureNote"), properties); // Tested properties.Clear(); properties.Add(dateCreated); ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("ScrDraft"), properties); properties.Clear(); properties.Add("RunDate"); ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("ScrCheckRun"), properties); DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Change all guids to lowercase to help the Chorus diff/merge code. /// </summary> /// ------------------------------------------------------------------------------------ public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository) { DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000024); const string dateCreated = "DateCreated"; var properties = new List <string> { dateCreated, "DateModified" }; ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("CmProject"), properties); // Tested ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("CmMajorObject"), properties); // Tested ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("CmPossibility"), properties); // Tested ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("CmAnnotation"), properties); // Tested ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("StJournalText"), properties); // Tested ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("LexEntry"), properties); // Tested ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("RnGenericRec"), properties); // Tested // Since ScrScriptureNote derives from CmBaseAnnotation, which has already had it DateCreated & DateModified updated, // we have to clear those two out of the dictioanry, or they will be updated twice, and the test on ScrScriptureNote will fail. properties.Clear(); properties.Add("DateResolved"); ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("ScrScriptureNote"), properties); // Tested properties.Clear(); properties.Add(dateCreated); ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("ScrDraft"), properties); properties.Clear(); properties.Add("RunDate"); ConvertClassAndSubclasses(domainObjectDtoRepository, domainObjectDtoRepository.AllInstancesWithSubclasses("ScrCheckRun"), properties); DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository); }
/// <summary> /// The weather list is used, so convert it to a custom (unowned) list, create a new /// custom field for RnGenericRec elements, and convert any Weather elements to that /// new custom field. /// </summary> private void ConvertWeatherToCustomListAndField(IDomainObjectDTORepository repoDTO) { // Change the Weather list to being unowned. DomainObjectDTO dtoLP = null; foreach (var dto in repoDTO.AllInstancesWithSubclasses("LangProject")) { dtoLP = dto; break; } string sWeatherListGuid = RemoveWeatherConditionsElement(dtoLP).ToLowerInvariant(); repoDTO.Update(dtoLP); DomainObjectDTO dtoWeatherList = null; foreach (var dto in repoDTO.AllInstancesWithSubclasses("CmPossibilityList")) { if (dto.Guid.ToLowerInvariant() == sWeatherListGuid) { dtoWeatherList = dto; break; } } dtoWeatherList.Xml = RemoveOwnerGuid(dtoWeatherList.Xml); repoDTO.Update(dtoWeatherList); // Create the custom field. string fieldName = "Weather"; while (repoDTO.IsFieldNameUsed("RnGenericRec", fieldName)) { fieldName = fieldName + "A"; } repoDTO.CreateCustomField("RnGenericRec", fieldName, SIL.CoreImpl.CellarPropertyType.ReferenceCollection, CmPossibilityTags.kClassId, "originally a standard part of Data Notebook records", WritingSystemServices.kwsAnals, new Guid(sWeatherListGuid)); string customStart = String.Format("<Custom name=\"{0}\">", fieldName); // Remove any empty Weather elements in the RnGenericRec objects, and convert // nonempty ones to custom elements. foreach (var dto in repoDTO.AllInstancesWithSubclasses("RnGenericRec")) { string sXml = dto.Xml; int idx = sXml.IndexOf("<Weather"); if (idx > 0) { string sXmlT = RemoveEmptyWeather(sXml, idx); if (sXmlT == sXml) { sXmlT = sXml.Replace("<Weather>", customStart); sXmlT = sXmlT.Replace("</Weather>", "</Custom>"); } dto.Xml = sXmlT; repoDTO.Update(dto); } } }
internal static void AddDefaultLexEntryRefType(IDomainObjectDTORepository repoDto) { var cmPossListGuidForComplexFormType = "1ee09905-63dd-4c7a-a9bd-1d496743ccd6"; var cmPossListGuidForVariantEntryType = "bb372467-5230-43ef-9cc7-4d40b053fb94"; const string unspecComplexEntryTypeGuid = "fec038ed-6a8c-4fa5-bc96-a4f515a98c50"; const string unspecVariantEntryTypeGuid = "3942addb-99fd-43e9-ab7d-99025ceb0d4e"; foreach (var dto in repoDto.AllInstancesWithSubclasses("LexEntryRef")) { var data = XElement.Parse(dto.Xml); var refTypeElt = data.Element("RefType"); var varientEntryTypeElt = data.Element("VariantEntryTypes"); var complexEntryTypeElt = data.Element("ComplexEntryTypes"); if (refTypeElt == null) { continue; } if (refTypeElt.FirstAttribute.Value == LexEntryRefTags.krtComplexForm.ToString() && complexEntryTypeElt == null) { AddRefType(data, repoDto, dto, "ComplexEntryTypes", unspecComplexEntryTypeGuid, false); } else if (refTypeElt.FirstAttribute.Value == LexEntryRefTags.krtVariant.ToString() && varientEntryTypeElt == null) { AddRefType(data, repoDto, dto, "VariantEntryTypes", unspecVariantEntryTypeGuid, false); } } foreach (var dto in repoDto.AllInstancesWithSubclasses("CmPossibilityList")) { var data = XElement.Parse(dto.Xml); var nameElt = data.Element("Name"); if (nameElt != null && nameElt.Value.StartsWith("Variant Types")) { cmPossListGuidForVariantEntryType = dto.Guid; AddRefType(data, repoDto, dto, "Possibilities", unspecVariantEntryTypeGuid, true); } else if (nameElt != null && nameElt.Value.StartsWith("Complex Form Types")) { cmPossListGuidForComplexFormType = dto.Guid; AddRefType(data, repoDto, dto, "Possibilities", unspecComplexEntryTypeGuid, true); } } var dateForTypeCreation = new DateTime(2016, 10, 3, 15, 0, 0); CreateLexEntryType(repoDto, unspecVariantEntryTypeGuid, cmPossListGuidForVariantEntryType, "unspec. var. of", "Unspecified Variant", "unspec. var.", dateForTypeCreation); CreateLexEntryType(repoDto, unspecComplexEntryTypeGuid, cmPossListGuidForComplexFormType, "unspec. comp. form of", "Unspecified Complex Form", "unspec. comp. form", dateForTypeCreation); }
private void CleanOutBadRefTypes(IDomainObjectDTORepository repoDto) { const string unspecComplexEntryTypeGuid = "fec038ed-6a8c-4fa5-bc96-a4f515a98c50"; const string unspecVariantEntryTypeGuid = "3942addb-99fd-43e9-ab7d-99025ceb0d4e"; foreach (var dto in repoDto.AllInstancesWithSubclasses("LexEntryRef")) { var data = XElement.Parse(dto.Xml); var refTypeElt = data.Element("RefType"); var varientEntryTypeElt = data.Element("VariantEntryTypes"); var complexEntryTypeElt = data.Element("ComplexEntryTypes"); if (refTypeElt.FirstAttribute.Value == LexEntryRefTags.krtComplexForm.ToString() && varientEntryTypeElt != null) { varientEntryTypeElt.Remove(); DataMigrationServices.UpdateDTO(repoDto, dto, data.ToString()); } else if (refTypeElt.FirstAttribute.Value == LexEntryRefTags.krtVariant.ToString() && complexEntryTypeElt != null) { complexEntryTypeElt.Remove(); DataMigrationServices.UpdateDTO(repoDto, dto, data.ToString()); } // Re-do the DM69 bit correctly if necessary if (refTypeElt.FirstAttribute.Value == LexEntryRefTags.krtComplexForm.ToString() && complexEntryTypeElt == null) { DataMigration7000069.AddRefType(data, repoDto, dto, "ComplexEntryTypes", unspecComplexEntryTypeGuid, false); } else if (refTypeElt.FirstAttribute.Value == LexEntryRefTags.krtVariant.ToString() && varientEntryTypeElt == null) { DataMigration7000069.AddRefType(data, repoDto, dto, "VariantEntryTypes", unspecVariantEntryTypeGuid, false); } } }
private List <String> GetAllExternalLinksInTsStrings(IDomainObjectDTORepository dtoRepos) { var filesPathsInTsStrings = new List <String>(); foreach (var dto in dtoRepos.AllInstancesWithSubclasses("CmObject")) //Get the Elements for all CmObjects { if (!dto.Xml.Contains("externalLink")) { continue; } //byte[] matchString = Encoding.UTF8.GetBytes("externalLink"); //if (!dto.XmlBytes.Contains(matchString)) // continue; var dtoXML = XElement.Parse(dto.Xml); foreach (var runXMLElement in dtoXML.XPathSelectElements("//Run")) { var externalLinkAttributeForThisRun = runXMLElement.Attribute("externalLink"); if (externalLinkAttributeForThisRun != null) { filesPathsInTsStrings.Add(externalLinkAttributeForThisRun.Value); //Check the path and if it is a rooted path which is relative to the LinkedFilesRootDir //then we will have to confirm that is was changed to a relative path after the migration. } } } return(filesPathsInTsStrings); }
private DomainObjectDTO GetDtoLangProj(IDomainObjectDTORepository repoDTO) { DomainObjectDTO dtoLP = null; foreach (var dto in repoDTO.AllInstancesWithSubclasses("LangProject")) { dtoLP = dto; break; } return(dtoLP); }
private bool IsWeatherUsed(IDomainObjectDTORepository repoDTO, List <DomainObjectDTO> collectOverlaysToRemove) { DomainObjectDTO dtoLP = GetDtoLangProj(repoDTO); string sLpXml = dtoLP.Xml; int idxW = sLpXml.IndexOf("<WeatherConditions>"); var sguidWeather = ExtractFirstGuid(sLpXml, idxW, " guid=\""); DomainObjectDTO dtoWeather = repoDTO.GetDTO(sguidWeather); var weatherItems = new HashSet <string>(); CollectItems(repoDTO, dtoWeather, weatherItems); foreach (var dto in repoDTO.AllInstancesWithSubclasses("RnGenericRec")) { string sXml = dto.Xml; int idx = sXml.IndexOf("<Weather>"); if (idx > 0) { int idxEnd = sXml.IndexOf("</Weather>"); if (idxEnd > idx) { string s = sXml.Substring(idx, idxEnd - idx); if (s.Contains("<objsur ")) { return(true); } } } bool dummy = false; if (StringContainsRefToItemInList("PhraseTags", weatherItems, sXml, ref dummy)) { return(true); } } foreach (var dto in repoDTO.AllInstancesSansSubclasses("CmOverlay")) { string sXml = dto.Xml; bool hasOtherItems = false; bool hasWeatherRef = StringContainsRefToItemInList("PossItems", weatherItems, sXml, ref hasOtherItems); var weatherListSet = new HashSet <string>(); weatherListSet.Add(sguidWeather.ToLowerInvariant()); hasWeatherRef |= StringContainsRefToItemInList("PossList", weatherListSet, sXml, ref hasOtherItems); if (hasWeatherRef) { if (hasOtherItems) { return(true); // an overlay with a mixture of weather and non-weather items is a problem } // One with only weather refs (and not used, since we know nothing is tagged to weather) // will be deleted. collectOverlaysToRemove.Add(dto); } } return(false); }
internal static void RemoveEmptyLexEntryRefs(IDomainObjectDTORepository repoDto) { foreach (var dto in repoDto.AllInstancesWithSubclasses("LexEntryRef")) { XElement data = XElement.Parse(dto.Xml); var components = data.Element("ComponentLexemes"); if (components == null || !components.HasElements) { DataMigrationServices.RemoveIncludingOwnedObjects(repoDto, dto, true); } } }
/// <summary> /// The Weather list is never used, so delete it (and remove any empty Weather elements /// from the RnGenericRec elements). /// </summary> private void DeleteWeatherListAndField(IDomainObjectDTORepository repoDTO) { // Remove the Weather list. DomainObjectDTO dtoLP = GetDtoLangProj(repoDTO); string sWeatherListGuid = RemoveWeatherConditionsElement(dtoLP).ToLowerInvariant(); repoDTO.Update(dtoLP); DomainObjectDTO dtoDeadList = null; foreach (var dto in repoDTO.AllInstancesWithSubclasses("CmPossibilityList")) { if (dto.Guid.ToLowerInvariant() == sWeatherListGuid) { dtoDeadList = dto; break; } } List <DomainObjectDTO> rgdtoDead = new List <DomainObjectDTO>(); GatherDeadObjects(repoDTO, dtoDeadList, rgdtoDead); foreach (var dto in rgdtoDead) { repoDTO.Remove(dto); } // Remove any empty Weather elements in the RnGenericRec objects. foreach (var dto in repoDTO.AllInstancesWithSubclasses("RnGenericRec")) { string sXml = dto.Xml; int idx = sXml.IndexOf("<Weather"); if (idx > 0) { dto.Xml = RemoveEmptyWeather(sXml, idx); repoDTO.Update(dto); } } }
/// <summary> /// Remove the collection of ReversalIndexEntry from each Sense /// </summary> public void RemoveReversalEntriesFromSenses(IDomainObjectDTORepository repoDto) { // Get all the LexSense Classes var allLexSenses = repoDto.AllInstancesWithSubclasses("LexSense"); foreach (var aLexSense in allLexSenses) { var lexSenseElement = XElement.Parse(aLexSense.Xml); // Remove Reversal Entries if exists lexSenseElement.Element("ReversalEntries")?.Remove(); // Update the LexSense Element DataMigrationServices.UpdateDTO(repoDto, aLexSense, lexSenseElement.ToString()); } }
/// <summary> /// Verify that the ComplexEntryTypes and VariantEntryTypes lists contain all of the /// standard LexEntryType objects, and that that they point only to valid LexEntryType /// objects. /// </summary> private void VerifyTypeLists(IDomainObjectDTORepository repoDto) { foreach (var dtoList in repoDto.AllInstancesWithSubclasses("CmPossibilityList")) { var xeList = XElement.Parse(dtoList.Xml); foreach (var objsur in xeList.XPathSelectElements("Possibilities/objsur")) { var xaGuid = objsur.Attribute("guid"); Assert.IsNotNull(xaGuid, "objsur elements should always have a guid attribute."); var guid = xaGuid.Value; DomainObjectDTO dtoPoss; Assert.IsTrue(repoDto.TryGetValue(guid, out dtoPoss), "Possibility Lists should point to valid objects."); VerifySubpossibilities(repoDto, dtoPoss); } } }
/// <summary> /// Add the reference collection of Senses to each reversal index /// and fill it with the Senses that referenced the ReversalIndexEntry /// </summary> public void AddSensesToReversalIndexEntry(IDomainObjectDTORepository repoDto) { // Get all the LexSense Classes var allLexSenses = repoDto.AllInstancesWithSubclasses("LexSense"); foreach (var aLexSense in allLexSenses) { var lexSenseElement = XElement.Parse(aLexSense.Xml); // Get the ReversalEntries within the LexSense var reversalEntries = lexSenseElement.Element("ReversalEntries"); if (reversalEntries == null) { continue; } // Get the Current LexSense's Guid var lexSenseGuid = lexSenseElement.Attribute("guid")?.Value; Debug.Assert(lexSenseGuid != null, "lexSenseGuid != null"); // Loop through the ReversalEntries within the LexSense var reversalEntriesList = reversalEntries.Elements("objsur"); foreach (var aReversalEntry in reversalEntriesList) { // Get the Current ReversalEntries (objsur) Guid from the objsur var reversalEntryGuid = aReversalEntry.Attribute("guid")?.Value; // Get the Reversal Entry Object, that has the specified Guid, that needs to be modified var aReversalIndexEntry = repoDto.GetDTO(reversalEntryGuid); // Add Senses to the Reversal Entry var reversalIndexElement = XElement.Parse(aReversalIndexEntry.Xml); var sensesElement = reversalIndexElement.Element("Senses"); if (sensesElement == null) { sensesElement = new XElement("Senses"); reversalIndexElement.Add(sensesElement); } var objsur = new XElement("objsur", new XAttribute("guid", lexSenseGuid), new XAttribute("t", "r")); sensesElement.Add(objsur); // Update the Reversal Entry DataMigrationServices.UpdateDTO(repoDto, aReversalIndexEntry, reversalIndexElement.ToString()); } } }
/// <summary> /// Verify that every LexEntryType points back to a valid owner after migration, and that /// the owner points to the LexEntryType. /// </summary> /// <param name="repoDto"></param> private static void VerifyEntryTypeOwners(IDomainObjectDTORepository repoDto) { foreach (var dto in repoDto.AllInstancesWithSubclasses("LexEntryType")) { DomainObjectDTO dtoOwner; Assert.IsTrue(repoDto.TryGetOwner(dto.Guid, out dtoOwner), "All entry types should have valid owners!"); DomainObjectDTO dtoOwnedOk = null; foreach (var dtoT in repoDto.GetDirectlyOwnedDTOs(dtoOwner.Guid)) { if (dtoT == dto) { dtoOwnedOk = dtoT; break; } } Assert.AreEqual(dto, dtoOwnedOk, "The owner should own the entry type!"); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Add DateModified to StText /// </summary> /// <param name="domainObjectDtoRepository"> /// Repository of all CmObject DTOs available for one migration step. /// </param> /// ------------------------------------------------------------------------------------ public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository) { DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000035); foreach (var stTextDTO in domainObjectDtoRepository.AllInstancesWithSubclasses("StText")) { XElement stText = XElement.Parse(stTextDTO.Xml); if (stText.Element("DateModified") != null) continue; // Already has a DateModified property (probably an StJounalText XElement dateModified = new XElement("DateModified", null); XAttribute value = new XAttribute("val", ReadWriteServices.FormatDateTime(DateTime.Now)); dateModified.Add(value); stText.Add(dateModified); DataMigrationServices.UpdateDTO(domainObjectDtoRepository, stTextDTO, stText.ToString()); } DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository); }
/// <summary> /// Change ReferringSenses To Senses under VirtualOrdering objects, if present /// </summary> public void ChangeReferringSensesToSenses(IDomainObjectDTORepository repoDto) { // Get all the VirtualOrdering Classes var allOrderings = repoDto.AllInstancesWithSubclasses("VirtualOrdering"); foreach (var anOrdering in allOrderings) { var orderingElement = XElement.Parse(anOrdering.Xml); var uniValue = orderingElement.Element("Field")?.Element("Uni"); // Change ReferringSenses Value as Senses if (uniValue?.Value == "ReferringSenses") { uniValue.Value = "Senses"; } // Update the VirtualOrdering Element DataMigrationServices.UpdateDTO(repoDto, anOrdering, orderingElement.ToString()); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Add DateModified to StText /// </summary> /// <param name="domainObjectDtoRepository"> /// Repository of all CmObject DTOs available for one migration step. /// </param> /// ------------------------------------------------------------------------------------ public void PerformMigration(IDomainObjectDTORepository domainObjectDtoRepository) { DataMigrationServices.CheckVersionNumber(domainObjectDtoRepository, 7000035); foreach (var stTextDTO in domainObjectDtoRepository.AllInstancesWithSubclasses("StText")) { XElement stText = XElement.Parse(stTextDTO.Xml); if (stText.Element("DateModified") != null) { continue; // Already has a DateModified property (probably an StJounalText } XElement dateModified = new XElement("DateModified", null); XAttribute value = new XAttribute("val", ReadWriteServices.FormatDateTime(DateTime.Now)); dateModified.Add(value); stText.Add(dateModified); DataMigrationServices.UpdateDTO(domainObjectDtoRepository, stTextDTO, stText.ToString()); } DataMigrationServices.IncrementVersionNumber(domainObjectDtoRepository); }
private void VerifyNoDirectFormatting(IDomainObjectDTORepository repoDTO) { byte[] rgbRun = Encoding.UTF8.GetBytes("<Run "); foreach (DomainObjectDTO dto in repoDTO.AllInstancesWithValidClasses()) { if (dto.XmlBytes.IndexOfSubArray(rgbRun) <= 0) { continue; } XElement xeObj = XElement.Parse(dto.Xml); foreach (XElement xe in xeObj.Descendants("Run")) { foreach (XAttribute xa in xe.Attributes()) { Assert.IsTrue(xa.Name.LocalName == "ws" || xa.Name.LocalName == "namedStyle" || xa.Name.LocalName == "externalLink", "only ws, namedStyle, and externalLink should exist as Run attributes in the test data"); } } } byte[] rgbStyleRules = Encoding.UTF8.GetBytes("<StyleRules>"); foreach (DomainObjectDTO dto in repoDTO.AllInstancesWithSubclasses("StTxtPara")) { if (dto.XmlBytes.IndexOfSubArray(rgbStyleRules) <= 0) { continue; } XElement xeObj = XElement.Parse(dto.Xml); foreach (XElement xe in xeObj.Descendants("Prop")) { foreach (XAttribute xa in xe.Attributes()) { Assert.AreEqual("namedStyle", xa.Name.LocalName, "Direct formatting of paragraphs should not exist (" + xa.Name + ")"); } } } }
/// <summary> /// Verify that all LexEntryRef objects point to valid LexEntryType objects. /// </summary> private void VerifyLexEntryRefs(IDomainObjectDTORepository repoDto) { foreach (var dtoRef in repoDto.AllInstancesWithSubclasses("LexEntryRef")) { var xeRef = XElement.Parse(dtoRef.Xml); foreach (var objsur in xeRef.XPathSelectElements("ComplexEntryTypes/objsur")) { var xaGuid = objsur.Attribute("guid"); Assert.IsNotNull(xaGuid, "objsur elements should always have a guid attribute."); var guid = xaGuid.Value; DomainObjectDTO dtoType; Assert.IsTrue(repoDto.TryGetValue(guid, out dtoType), "LexEntryRef.ComplexEntryTypes should point to valid objects."); } foreach (var objsur in xeRef.XPathSelectElements("VariantEntryTypes/objsur")) { var xaGuid = objsur.Attribute("guid"); Assert.IsNotNull(xaGuid, "objsur elements should always have a guid attribute."); var guid = xaGuid.Value; DomainObjectDTO dtoType; Assert.IsTrue(repoDto.TryGetValue(guid, out dtoType), "LexEntryRef.VariantEntryTypes should point to valid objects."); } } }
internal static void AddReverseNameAndSwapAbbreviationFields(IDomainObjectDTORepository repoDto) { // We DO want subclasses (e.g. LexEntryInflType) foreach (var dto in repoDto.AllInstancesWithSubclasses("LexEntryType")) { var data = XElement.Parse(dto.Xml); var nameElt = data.Element("Name"); if (nameElt != null) { var nameAUniElt = nameElt.Elements("AUni").FirstOrDefault(elt => elt.Attribute("ws").Value == "en"); if (nameAUniElt != null) { var revNameElt = new XElement("ReverseName"); var auni = new XElement("AUni"); auni.SetAttributeValue("ws", "en"); auni.Value = nameAUniElt.Value + " of"; revNameElt.Add(auni); data.Add(revNameElt); } } var abbrevElt = data.Element("Abbreviation"); var revAbbrElt = data.Element("ReverseAbbr"); if (abbrevElt != null) { abbrevElt.Name = "ReverseAbbr"; } if (revAbbrElt != null) { revAbbrElt.Name = "Abbreviation"; } DataMigrationServices.UpdateDTO(repoDto, dto, data.ToString()); } }
private static void ConvertAllRefsToStrings(IDomainObjectDTORepository domainObjectDtoRepository, string className, Dictionary<string, Tuple<string, DomainObjectDTO, XElement>> guidToWsInfo, HashSet<string> referencedWsIds) { foreach (DomainObjectDTO dto in domainObjectDtoRepository.AllInstancesWithSubclasses(className)) { XElement elem = XElement.Parse(dto.Xml); if (ConvertRefToString(elem.Element("WritingSystem"), guidToWsInfo, referencedWsIds)) DataMigrationServices.UpdateDTO(domainObjectDtoRepository, dto, elem.ToString()); } }
private static void ConvertAllIcuLocalesToLangTags(IDomainObjectDTORepository domainObjectDtoRepository, string className, HashSet<string> referencedWsIds) { foreach (DomainObjectDTO dto in domainObjectDtoRepository.AllInstancesWithSubclasses(className)) { XElement elem = XElement.Parse(dto.Xml); XElement icuLocaleElem = elem.Element("ICULocale"); if (icuLocaleElem != null) { string wsId = Version19LangTagUtils.ToLangTag((string) icuLocaleElem.Element("Uni")); icuLocaleElem.AddAfterSelf(new XElement("WritingSystem", new XElement("Uni", wsId))); icuLocaleElem.Remove(); DataMigrationServices.UpdateDTO(domainObjectDtoRepository, dto, elem.ToString()); referencedWsIds.Add(wsId); } } }
private void VerifyNoDirectFormatting(IDomainObjectDTORepository repoDTO) { byte[] rgbRun = Encoding.UTF8.GetBytes("<Run "); foreach (DomainObjectDTO dto in repoDTO.AllInstancesWithValidClasses()) { if (dto.XmlBytes.IndexOfSubArray(rgbRun) <= 0) continue; XElement xeObj = XElement.Parse(dto.Xml); foreach (XElement xe in xeObj.Descendants("Run")) { foreach (XAttribute xa in xe.Attributes()) { Assert.IsTrue(xa.Name.LocalName == "ws" || xa.Name.LocalName == "namedStyle" || xa.Name.LocalName == "externalLink", "only ws, namedStyle, and externalLink should exist as Run attributes in the test data"); } } } byte[] rgbStyleRules = Encoding.UTF8.GetBytes("<StyleRules>"); foreach (DomainObjectDTO dto in repoDTO.AllInstancesWithSubclasses("StTxtPara")) { if (dto.XmlBytes.IndexOfSubArray(rgbStyleRules) <= 0) continue; XElement xeObj = XElement.Parse(dto.Xml); foreach (XElement xe in xeObj.Descendants("Prop")) { foreach (XAttribute xa in xe.Attributes()) { Assert.AreEqual("namedStyle", xa.Name.LocalName, "Direct formatting of paragraphs should not exist (" + xa.Name + ")"); } } } }
private List<String> GetAllExternalLinksInTsStrings(IDomainObjectDTORepository dtoRepos) { var filesPathsInTsStrings = new List<String>(); foreach (var dto in dtoRepos.AllInstancesWithSubclasses("CmObject")) //Get the Elements for all CmObjects { if (!dto.Xml.Contains("externalLink")) continue; //byte[] matchString = Encoding.UTF8.GetBytes("externalLink"); //if (!dto.XmlBytes.Contains(matchString)) // continue; var dtoXML = XElement.Parse(dto.Xml); foreach (var runXMLElement in dtoXML.XPathSelectElements("//Run")) { var externalLinkAttributeForThisRun = runXMLElement.Attribute("externalLink"); if (externalLinkAttributeForThisRun != null) { filesPathsInTsStrings.Add(externalLinkAttributeForThisRun.Value); //Check the path and if it is a rooted path which is relative to the LinkedFilesRootDir //then we will have to confirm that is was changed to a relative path after the migration. } } } return filesPathsInTsStrings; }
private void FixOwnershipOfSubtypes(IDomainObjectDTORepository repoDto) { var types = repoDto.AllInstancesWithSubclasses("LexEntryType"); var cFixedFirst = 0; foreach (var dto in types) { var xml = dto.Xml; var fFixed = false; foreach (var badGuid in m_mapBadGoodGuids.Keys) { if (xml.Contains(badGuid)) { var bad = String.Format("guid=\"{0}\"", badGuid); var good = String.Format("guid=\"{0}\"", m_mapBadGoodGuids[badGuid]); xml = xml.Replace(bad, good); var bad2 = String.Format("guid='{0}'", badGuid); var good2 = String.Format("guid='{0}'", m_mapBadGoodGuids[badGuid]); xml = xml.Replace(bad2, good2); // probably pure paranoia... fFixed = true; } } if (fFixed) { dto.Xml = xml; repoDto.Update(dto); ++cFixedFirst; } var cFixed = 0; foreach (var dtoSub in repoDto.GetDirectlyOwnedDTOs(dto.Guid)) { DomainObjectDTO dtoOwner; if (!repoDto.TryGetOwner(dtoSub.Guid, out dtoOwner) || dtoOwner != dto) { // we have a broken ownership link -- fix it! var xeSub = XElement.Parse(dtoSub.Xml); var xaOwner = xeSub.Attribute("ownerguid"); if (xaOwner == null) xeSub.Add(new XAttribute("ownerguid", dto.Guid)); else xaOwner.Value = dto.Guid; dtoSub.Xml = xeSub.ToString(); repoDto.Update(dtoSub); ++cFixed; } } } }
private void ChangeInvalidGuid(IDomainObjectDTORepository repoDto, LexTypeInfo info, string name, string guidStd) { var xaGuid = info.XmlElement.Attribute("guid"); if (xaGuid == null) throw new Exception("The object does not have a guid -- this is impossible!"); xaGuid.SetValue(guidStd); var guidBad = info.DTO.Guid; if (!m_mapBadGoodGuids.ContainsKey(guidBad)) m_mapBadGoodGuids.Add(guidBad, guidStd); var className = info.DTO.Classname; repoDto.Remove(info.DTO); info.DTO = new DomainObjectDTO(guidStd, className, info.XmlElement.ToString()); repoDto.Add(info.DTO); // Fix the owning reference (but only if it's one of the two lists, because otherwise // it might be contained in a LexTypeInfo that hasn't yet been processed). var bad = String.Format("guid=\"{0}\"", guidBad); var good = String.Format("guid=\"{0}\"", guidStd); var bad2 = String.Format("guid='{0}'", guidBad); // probably pure paranoia... var good2 = String.Format("guid='{0}'", guidStd); DomainObjectDTO dtoOwner; if (repoDto.TryGetOwner(info.DTO.Guid, out dtoOwner) && dtoOwner.Classname == "CmPossibilityList") { dtoOwner.Xml = dtoOwner.Xml.Replace(bad, good).Replace(bad2, good2); repoDto.Update(dtoOwner); } // Fix any references from LexEntryRef objects. foreach (var dtoRef in repoDto.AllInstancesWithSubclasses("LexEntryRef")) { var xml = dtoRef.Xml; if (xml.Contains(guidBad)) { dtoRef.Xml = xml.Replace(bad, good).Replace(bad2, good2); repoDto.Update(dtoRef); } } m_mapNameGuid.Remove(name); m_mapGuidName.Remove(guidStd); }
/// <summary> /// Creates a CmPossibilityList with all the basic properties filled in for the xml (necessary for S/R) and adds it to the dto /// </summary> /// <param name="dtoRepo">the created list will be added to this IDomainObjectDTORepository</param> /// <param name="listGuid">guid to use for this list</param> /// <param name="ownerGuid">guid of the object that owns this list</param> /// <param name="languageAbbrAndNames">Tuple of language id, abbreviation, and name for the list</param> /// <param name="createTime">DateTime to use as the DateCreated and DateModified for this list</param> /// <param name="wsSelector">e.g. WritingSystemServices.kwsVernAnals</param> /// <param name="possibilityItems">array of guids for possibilityItems to add if any</param> /// <param name="itemType">the class id of items which this list can contain, defaults to 7 (CmPossibility)</param> public static void CreatePossibilityList(IDomainObjectDTORepository dtoRepo, string listGuid, string ownerGuid, Tuple <string, string, string>[] languageAbbrAndNames, DateTime createTime, int wsSelector, string[] possibilityItems = null, int itemType = 7) { var existingList = FindMatchingCustomList(dtoRepo.AllInstancesWithSubclasses("CmPossibilityList"), languageAbbrAndNames); if (existingList != null) { var listElement = XElement.Parse(existingList.Xml); var names = listElement.Elements("Name"); foreach (var titleElement in names.Select(name => name.Element("AUni")).Where(titleElement => titleElement != null)) { titleElement.Value = titleElement.Value + "-Custom"; } UpdateDTO(dtoRepo, existingList, listElement.ToString()); } var sb = new StringBuilder(); sb.AppendFormat("<rt class=\"CmPossibilityList\" guid=\"{0}\" ownerguid=\"{1}\">", listGuid, ownerGuid); sb.Append("<Abbreviation>"); foreach (var abbr in languageAbbrAndNames) { sb.Append(string.Format("<AUni ws=\"{0}\">{1}</AUni>", abbr.Item1, abbr.Item2)); } sb.Append("</Abbreviation>"); sb.AppendFormat("<DateCreated val=\"{0:yyyy-MM-dd HH:mm:ss.fff}\" />", createTime); sb.AppendFormat("<DateModified val=\"{0:yyyy-MM-dd HH:mm:ss.fff}\" />", createTime); sb.Append("<Depth val=\"1\" />"); sb.Append("<DisplayOption val=\"0\" />"); sb.Append("<IsClosed val=\"False\" />"); sb.Append("<IsSorted val=\"True\" />"); sb.Append("<IsVernacular val=\"False\" />"); sb.Append("<ListVersion val=\"00000000-0000-0000-0000-000000000000\" />"); sb.AppendFormat("<ItemClsid val=\"{0}\" />", itemType); sb.Append("<Name>"); foreach (var abbr in languageAbbrAndNames) { sb.Append(string.Format("<AUni ws=\"{0}\">{1}</AUni>", abbr.Item1, abbr.Item3)); } sb.Append("</Name>"); if (possibilityItems != null) { sb.Append("<Possibilities>"); foreach (var possibilityGuid in possibilityItems) { sb.Append(string.Format("<objsur guid=\"{0}\" t=\"o\" />", possibilityGuid)); } sb.Append("</Possibilities>"); } sb.Append("<PreventChoiceAboveLevel val=\"0\" />"); sb.Append("<PreventDuplicates val=\"True\" />"); sb.Append("<PreventNodeChoices val=\"True\" />"); sb.Append("<UseExtendedFields val=\"False\" />"); sb.Append(string.Format("<WsSelector val=\"{0}\" />", wsSelector)); sb.Append("</rt>"); var newList = new DomainObjectDTO(listGuid, "CmPossibilityList", sb.ToString()); dtoRepo.Add(newList); }
private bool IsWeatherUsed(IDomainObjectDTORepository repoDTO, List<DomainObjectDTO> collectOverlaysToRemove) { DomainObjectDTO dtoLP = GetDtoLangProj(repoDTO); string sLpXml = dtoLP.Xml; int idxW = sLpXml.IndexOf("<WeatherConditions>"); var sguidWeather = ExtractFirstGuid(sLpXml, idxW, " guid=\""); DomainObjectDTO dtoWeather = repoDTO.GetDTO(sguidWeather); var weatherItems = new HashSet<string>(); CollectItems(repoDTO, dtoWeather, weatherItems); foreach (var dto in repoDTO.AllInstancesWithSubclasses("RnGenericRec")) { string sXml = dto.Xml; int idx = sXml.IndexOf("<Weather>"); if (idx > 0) { int idxEnd = sXml.IndexOf("</Weather>"); if (idxEnd > idx) { string s = sXml.Substring(idx, idxEnd - idx); if (s.Contains("<objsur ")) { return true; } } } bool dummy = false; if (StringContainsRefToItemInList("PhraseTags", weatherItems, sXml, ref dummy)) return true; } foreach (var dto in repoDTO.AllInstancesSansSubclasses("CmOverlay")) { string sXml = dto.Xml; bool hasOtherItems = false; bool hasWeatherRef = StringContainsRefToItemInList("PossItems", weatherItems, sXml, ref hasOtherItems); var weatherListSet = new HashSet<string>(); weatherListSet.Add(sguidWeather.ToLowerInvariant()); hasWeatherRef |= StringContainsRefToItemInList("PossList", weatherListSet, sXml, ref hasOtherItems); if (hasWeatherRef) { if (hasOtherItems) return true; // an overlay with a mixture of weather and non-weather items is a problem // One with only weather refs (and not used, since we know nothing is tagged to weather) // will be deleted. collectOverlaysToRemove.Add(dto); } } return false; }
private DomainObjectDTO GetDtoLangProj(IDomainObjectDTORepository repoDTO) { DomainObjectDTO dtoLP = null; foreach (var dto in repoDTO.AllInstancesWithSubclasses("LangProject")) { dtoLP = dto; break; } return dtoLP; }
private void RenameDuplicateCustomListsAndFixBadLists(IDomainObjectDTORepository repoDto) { var allLists = repoDto.AllInstancesWithSubclasses("CmPossibilityList"); var namesAndLists = new Dictionary <Tuple <string, string>, DomainObjectDTO>(); var duplicates = new List <Tuple <DomainObjectDTO, DomainObjectDTO> >(); foreach (var list in allLists) { var listElement = XElement.Parse(list.Xml); var name = listElement.Elements("Name"); var listTitles = name.Elements("AUni"); // Grab the elements which had bad numbers put in them and fix them saving the dto var displayOption = listElement.Elements("DisplayOption").FirstOrDefault(); if (displayOption != null) { PossNameType option; if (!Enum.TryParse(displayOption.Attribute("val").Value, out option) || !Enum.IsDefined(typeof(PossNameType), option)) { displayOption.SetAttributeValue("val", "0"); DataMigrationServices.UpdateDTO(repoDto, list, listElement.ToString()); } } var preventChoiceAbove = listElement.Elements("PreventChoiceAboveLevel").FirstOrDefault(); if (preventChoiceAbove != null) { int preventChoiceAboveVal = -1; if (!int.TryParse(preventChoiceAbove.Attribute("val").Value, out preventChoiceAboveVal) || preventChoiceAboveVal < 0) { preventChoiceAbove.SetAttributeValue("val", "0"); DataMigrationServices.UpdateDTO(repoDto, list, listElement.ToString()); } } foreach (var listTitle in listTitles) { var wsAttrValue = listTitle.Attribute("ws"); if (wsAttrValue == null) { continue; } var key = new Tuple <string, string>(wsAttrValue.Value, listTitle.Value); if (string.IsNullOrEmpty(key.Item2)) // If there is no actual name for a writing system ignore it { continue; } if (namesAndLists.ContainsKey(key)) { duplicates.Add(new Tuple <DomainObjectDTO, DomainObjectDTO>(namesAndLists[key], list)); } else { namesAndLists.Add(key, list); } } } // This code assumes that one of the duplicates is a custom list which has no ownerguid, the other created by a DM must be owned by LexDb foreach (var duplicate in duplicates) { var listOne = XElement.Parse(duplicate.Item1.Xml); var listTwo = XElement.Parse(duplicate.Item2.Xml); if (listOne.Attribute("ownerguid") != null) { AppendCustomToNamesAndUpdate(repoDto, duplicate.Item2, listTwo); } else { AppendCustomToNamesAndUpdate(repoDto, duplicate.Item1, listOne); } } }
/// <summary> /// The weather list is used, so convert it to a custom (unowned) list, create a new /// custom field for RnGenericRec elements, and convert any Weather elements to that /// new custom field. /// </summary> private void ConvertWeatherToCustomListAndField(IDomainObjectDTORepository repoDTO) { // Change the Weather list to being unowned. DomainObjectDTO dtoLP = null; foreach (var dto in repoDTO.AllInstancesWithSubclasses("LangProject")) { dtoLP = dto; break; } string sWeatherListGuid = RemoveWeatherConditionsElement(dtoLP).ToLowerInvariant(); repoDTO.Update(dtoLP); DomainObjectDTO dtoWeatherList = null; foreach (var dto in repoDTO.AllInstancesWithSubclasses("CmPossibilityList")) { if (dto.Guid.ToLowerInvariant() == sWeatherListGuid) { dtoWeatherList = dto; break; } } dtoWeatherList.Xml = RemoveOwnerGuid(dtoWeatherList.Xml); repoDTO.Update(dtoWeatherList); // Create the custom field. string fieldName = "Weather"; while (repoDTO.IsFieldNameUsed("RnGenericRec", fieldName)) fieldName = fieldName + "A"; repoDTO.CreateCustomField("RnGenericRec", fieldName, SIL.CoreImpl.CellarPropertyType.ReferenceCollection, CmPossibilityTags.kClassId, "originally a standard part of Data Notebook records", WritingSystemServices.kwsAnals, new Guid(sWeatherListGuid)); string customStart = String.Format("<Custom name=\"{0}\">", fieldName); // Remove any empty Weather elements in the RnGenericRec objects, and convert // nonempty ones to custom elements. foreach (var dto in repoDTO.AllInstancesWithSubclasses("RnGenericRec")) { string sXml = dto.Xml; int idx = sXml.IndexOf("<Weather"); if (idx > 0) { string sXmlT = RemoveEmptyWeather(sXml, idx); if (sXmlT == sXml) { sXmlT = sXml.Replace("<Weather>", customStart); sXmlT = sXmlT.Replace("</Weather>", "</Custom>"); } dto.Xml = sXmlT; repoDTO.Update(dto); } } }
/// <summary> /// Verify that the ComplexEntryTypes and VariantEntryTypes lists contain all of the /// standard LexEntryType objects, and that that they point only to valid LexEntryType /// objects. /// </summary> private void VerifyTypeLists(IDomainObjectDTORepository repoDto) { foreach (var dtoList in repoDto.AllInstancesWithSubclasses("CmPossibilityList")) { var xeList = XElement.Parse(dtoList.Xml); foreach (var objsur in xeList.XPathSelectElements("Possibilities/objsur")) { var xaGuid = objsur.Attribute("guid"); Assert.IsNotNull(xaGuid, "objsur elements should always have a guid attribute."); var guid = xaGuid.Value; string name; DomainObjectDTO dtoPoss; Assert.IsTrue(repoDto.TryGetValue(guid, out dtoPoss), "Possibility Lists should point to valid objects."); VerifySubpossibilities(repoDto, dtoPoss); } } }
private static void ProcessParagraphs( IDomainObjectDTORepository dtoRepos, IDictionary<string, byte[]> oldCCAs, IEnumerable<KeyValuePair<byte[], XElement>> halfBakedCcwgItems, IDictionary<string, SortedList<int, byte[]>> paraToOldSegments, IDictionary<string, SortedList<int, byte[]>> paraToOldXfics, IDictionary<Guid, Guid> ccaGuidMap, ICollection<byte[]> oldTextTags, Dictionary<string, List<byte[]>> freeTrans, Dictionary<string, List<byte[]>> litTrans, Dictionary<string, List<byte[]>> notes) { var dtos = dtoRepos.AllInstancesWithSubclasses("StTxtPara"); //var count = dtos.Count(); //var num = 0; //var cpara = 0; foreach (var currentParaDto in dtos) { //++num; // If it has no contents, then skip it. var stTxtParaBounds = new ElementBounds(currentParaDto.XmlBytes, s_tagsStTxtPara); if (!stTxtParaBounds.IsValid) continue; var contentsBounds = new ElementBounds(currentParaDto.XmlBytes, s_tagsContents, stTxtParaBounds.BeginTagOffset, stTxtParaBounds.EndTagOffset); if (!contentsBounds.IsValid) continue; //++cpara; // Mark the paragraph as needing retokenization. MarkParaAsNeedingTokenization(dtoRepos, currentParaDto); var currentParaGuid = currentParaDto.Guid.ToLower(); SortedList<int, byte[]> xficsForCurrentPara; paraToOldXfics.TryGetValue(currentParaGuid, out xficsForCurrentPara); SortedList<int, byte[]> segsForCurrentPara; if (!paraToOldSegments.TryGetValue(currentParaGuid, out segsForCurrentPara) && xficsForCurrentPara != null && xficsForCurrentPara.Count > 0) { // We have no segments at all, but there are xfics, so try to recover the broken data, // as much as possible. // Need to create a new old segment XElement (not dto), to try and and keep old data. var guidBrandNewSeg = Guid.NewGuid(); var brandNewSegGuid = guidBrandNewSeg.ToString().ToLower(); ccaGuidMap.Add(guidBrandNewSeg, guidBrandNewSeg); segsForCurrentPara = new SortedList<int, byte[]>(); paraToOldSegments.Add(currentParaGuid, segsForCurrentPara); var bldr = new StringBuilder(); bldr.AppendFormat("<rt guid=\"{0}\"", brandNewSegGuid); bldr.Append("<CmObject/>"); bldr.Append("<CmBaseAnnotation>"); bldr.Append("<BeginOffset val=\"0\"/>"); bldr.AppendFormat("<EndOffset val=\"{0}\"/>", int.MaxValue); bldr.Append("</CmBaseAnnotation>"); bldr.Append("</rt>"); segsForCurrentPara.Add(0, Encoding.UTF8.GetBytes(bldr.ToString())); } // If the para has no segs or xfics, skip the following work. if (segsForCurrentPara == null) continue; if (xficsForCurrentPara != null && xficsForCurrentPara.Count > 0 && segsForCurrentPara.Count > 0) { // We have both segments and xfics. Check for odd case (like FWR-3081) // where the first segment starts AFTER the first xfic, and add a new // segment that covers the text up to the first current segment. if (xficsForCurrentPara.First().Key < segsForCurrentPara.First().Key) AddExtraInitialSegment(currentParaGuid, ccaGuidMap, paraToOldSegments); } var halfBakedCcwgItemsForCurrentPara = new List<KeyValuePair<byte[], XElement>>(); List<string> writingSystems; var runs = GetParagraphContentRuns(currentParaDto.XmlBytes, out writingSystems); // We may well have segments with no xfics, for example, Scripture that has segmented BT. if (xficsForCurrentPara != null) { // Since pfics/wfics were 'optional' and usually not maintained in the db, // we need to make sure there is a dummy one in xficsForCurrentPara // in order to get the correct Begin/EndAnalysisIndex for chart and tagging objects // It turns out we don't need to worry about ws and exact begin/end character offsets. // All we need to end up with correct indices is the correct NUMBER of xfics. var context = new ParagraphContext(currentParaGuid, xficsForCurrentPara); EnsureAllXfics(runs, context); // Find any 'halfbaked' items for the current paragraph. // Get the para for the first objsur's guid (some twfic ann), // in the CmIndirectAnnotation's AppliesTo prop. foreach (var kvp in halfBakedCcwgItems) { var refs = GetAppliesToObjsurGuids(kvp.Key); if (refs == null || refs.Count == 0) continue; var guid = refs[0]; var dto = dtoRepos.GetDTO(guid); var guidBegin = GetBeginObjectGuid(dto.XmlBytes); if (guidBegin == currentParaGuid) halfBakedCcwgItemsForCurrentPara.Add(kvp); } } var bldrSegmentsElement = new StringBuilder(); var numberOfOldSegmentsInCurrentPara = segsForCurrentPara.Values.Count; var currentOldSegmentIdx = 1; foreach (var currentOldSegInCurrentPara in segsForCurrentPara.Values) { var isLastOldSegment = (currentOldSegmentIdx++ == numberOfOldSegmentsInCurrentPara); var oldSegGuid = GetGuid(currentOldSegInCurrentPara); var guidOldSeg = new Guid(oldSegGuid); var newSegGuid = ccaGuidMap[guidOldSeg].ToString().ToLowerInvariant(); // Add it to Segments prop of currentParaElement, var objsur = DataMigrationServices.CreateOwningObjSurElement(newSegGuid); bldrSegmentsElement.AppendLine(objsur.ToString()); // Create new XElement for new segment. var newSegmentElement = new XElement("rt", new XAttribute("class", "Segment"), new XAttribute("guid", newSegGuid), new XAttribute("ownerguid", currentParaDto.Guid.ToLower()), new XElement("CmObject"), new XElement("Segment", AddBeginOffset(GetBeginOffset(currentOldSegInCurrentPara)), AddFreeTranslation(oldSegGuid, freeTrans), AddLiteralTranslation(oldSegGuid, litTrans), AddNotes(dtoRepos, newSegGuid, oldSegGuid, notes), AddSegmentAnalyses(dtoRepos, halfBakedCcwgItemsForCurrentPara, currentOldSegInCurrentPara, xficsForCurrentPara, oldTextTags, newSegGuid, isLastOldSegment, currentParaDto))); newSegmentElement = DeleteTemporaryAnalyses(newSegmentElement); // Create a new Segment instance DTO from the 'newSegmentElement', // and add it to repos. var newSegDto = new DomainObjectDTO(newSegGuid, "Segment", newSegmentElement.ToString()); dtoRepos.Add(newSegDto); } paraToOldSegments.Remove(currentParaGuid.ToLower()); paraToOldXfics.Remove(currentParaGuid.ToLower()); if (bldrSegmentsElement.Length == 0) continue; bldrSegmentsElement.Insert(0, "<Segments>"); bldrSegmentsElement.Append("</Segments>"); // Add paraSegmentsElement to current para. var segBytes = Encoding.UTF8.GetBytes(bldrSegmentsElement.ToString()); var xmlNew = new List<byte>(currentParaDto.XmlBytes.Length + segBytes.Length); xmlNew.AddRange(currentParaDto.XmlBytes); stTxtParaBounds = new ElementBounds(currentParaDto.XmlBytes, s_tagsStTxtPara); xmlNew.InsertRange(stTxtParaBounds.EndTagOffset, segBytes); // Tell DTO repos about the modification. DataMigrationServices.UpdateDTO(dtoRepos, currentParaDto, xmlNew.ToArray()); } }