public Delta ToDelta(string projectId, XElement usxElem) { var newDelta = new Delta(); int nextNoteId = 0; var nextIds = new Dictionary <string, int>(); string curRef = null; string curChapter = null; string bookId = null; foreach (XElement elem in usxElem.Elements()) { switch (elem.Name.LocalName) { case "book": bookId = (string)elem.Attribute("code"); break; case "para": var style = (string)elem.Attribute("style"); bool paraStyle = IsParagraphStyle(style); if (paraStyle) { if (curRef != null) { int slashIndex = curRef.IndexOf("/", StringComparison.Ordinal); if (slashIndex != -1) { curRef = curRef.Substring(0, slashIndex); } curRef = GetParagraphRef(nextIds, curRef + "/" + style); } } else { curRef = GetParagraphRef(nextIds, style); } ProcessChildNodes(projectId, bookId, newDelta, elem, curChapter, ref curRef, ref nextNoteId); SegmentEnded(newDelta, curRef); if (!paraStyle) { curRef = null; } newDelta.InsertPara(GetAttributes(elem)); break; case "chapter": curRef = null; curChapter = (string)elem.Attribute("number"); newDelta.InsertChapter(curChapter, GetAttributes(elem)); break; default: LogUnknownElement(projectId, bookId, elem); break; } } newDelta.Insert("\n"); return(newDelta); }
public static Delta InsertBlank(this Delta delta, string segRef) { string type = segRef.Contains("/p") || segRef.Contains("/m") ? "initial" : "normal"; var attrs = new JObject(new JProperty("segment", segRef)); return(delta.Insert(new { blank = type }, attrs)); }
public static Delta InsertText(this Delta delta, string text, string segRef = null, JObject attributes = null) { if (segRef != null) { attributes = (JObject)attributes?.DeepClone() ?? new JObject(); attributes.Add(new JProperty("segment", segRef)); } return(delta.Insert(text, attributes)); }
public static Delta InsertText(this Delta delta, object text, string segRef) { var attrs = new JObject(); if (segRef != null) { attrs.Add(new JProperty("segment", segRef)); } return(delta.Insert(text, attrs)); }
public static Delta InsertNote(this Delta delta, int index, Delta noteDelta, object attributes, string segRef) { var deltaObj = new JObject(new JProperty("ops", new JArray(noteDelta.Ops))); var noteObj = new JObject( new JProperty("note", new JObject( new JProperty("index", index), new JProperty("delta", deltaObj)))); return(delta.Insert(noteObj, CreateAttributes("note", attributes, segRef))); }
public static Delta InsertCell(this Delta delta, int table, int row, string style, string align) { var attrs = new JObject( new JProperty("table", new JObject(new JProperty("id", $"table_{table}"))), new JProperty("row", new JObject(new JProperty("id", $"row_{table}_{row}"))), new JProperty("cell", new JObject( new JProperty("style", style), new JProperty("align", align)))); return(delta.Insert("\n", attrs)); }
public static Delta InsertEmbed(this Delta delta, string type, JObject obj, string segRef = null, JObject attributes = null) { var embed = new JObject(new JProperty(type, obj)); if (segRef != null) { attributes = (JObject)attributes?.DeepClone() ?? new JObject(); attributes.Add(new JProperty("segment", segRef)); } return(delta.Insert(embed, attributes)); }
private void ChapterEnded(List <ChapterDelta> chapterDeltas, Delta chapterDelta, bool isChapterValid, ParseState state) { if (state.ImpliedParagraph) { SegmentEnded(chapterDelta, state.CurRef); chapterDelta.Insert('\n'); state.ImpliedParagraph = false; } if (!int.TryParse(state.CurChapter, out int chapterNum)) { return; } chapterDeltas.Add(new ChapterDelta(chapterNum, state.LastVerse, isChapterValid, chapterDelta)); }
public static Delta InsertCell(this Delta delta, int table, int row, string style, string align, bool invalid = false) { var attrs = new JObject( new JProperty("table", new JObject(new JProperty("id", $"table_{table}"))), new JProperty("row", new JObject(new JProperty("id", $"row_{table}_{row}"))), new JProperty("cell", new JObject( new JProperty("style", style), new JProperty("align", align)))); if (invalid) { attrs.Add(new JProperty("invalid-block", true)); } return(delta.Insert("\n", attrs)); }
private void ProcessChildNode(Delta newDelta, XNode node, int curChapter, ref string lastVerse, ref string curRef, ref int tableIndex, JObject attributes = null) { switch (node) { case XElement elem: switch (elem.Name.LocalName) { case "para": ProcessChildNodes(newDelta, elem); newDelta.InsertPara(GetAttributes(elem)); break; case "verse": lastVerse = (string)elem.Attribute("number"); InsertVerse(newDelta, elem, curChapter, ref curRef); break; case "ref": var newRefAttributes = (JObject)attributes?.DeepClone() ?? new JObject(); newRefAttributes.Add(new JProperty(elem.Name.LocalName, GetAttributes(elem))); newDelta.InsertText(elem.Value, curRef, newRefAttributes); break; case "char": var newChildAttributes = (JObject)attributes?.DeepClone() ?? new JObject(); JToken existingCharAttrs = newChildAttributes["char"]; JObject newCharAttrs = GetAttributes(elem); if (existingCharAttrs == null) { newChildAttributes.Add(new JProperty(elem.Name.LocalName, newCharAttrs)); } else { switch (existingCharAttrs) { case JArray array: array.Add(newCharAttrs); break; case JObject obj: newChildAttributes[elem.Name.LocalName] = new JArray(obj, newCharAttrs); break; } } ProcessChildNodes(newDelta, elem, curChapter, ref lastVerse, ref curRef, ref tableIndex, newChildAttributes); break; case "table": tableIndex++; JObject tableAttributes = GetAttributes(elem); tableAttributes.Add(new JProperty("id", $"table_{tableIndex}")); int rowIndex = 1; foreach (XElement row in elem.Elements("row")) { var rowAttributes = new JObject(new JProperty("id", $"row_{tableIndex}_{rowIndex}")); foreach (XElement cell in row.Elements()) { ProcessChildNode(newDelta, cell, curChapter, ref lastVerse, ref curRef, ref tableIndex); var attrs = new JObject( new JProperty("table", tableAttributes), new JProperty("row", rowAttributes)); if (cell.Name.LocalName == "cell") { attrs.Add(new JProperty("cell", GetAttributes(cell))); } newDelta.Insert("\n", attrs); } rowIndex++; } break; case "cell": ProcessChildNodes(newDelta, elem, curChapter, ref lastVerse, ref curRef, ref tableIndex); break; default: InsertEmbed(newDelta, elem, curRef, attributes); break; } break; case XText text: newDelta.InsertText(text.Value, curRef, attributes); break; } }
public static Delta InsertPara(this Delta delta, object attributes) { return(delta.Insert("\n", CreateAttributes("para", attributes))); }
private void ProcessChildNode(HashSet <XNode> invalidNodes, Delta newDelta, XNode node, ParseState state, JObject attributes = null) { switch (node) { case XElement elem: switch (elem.Name.LocalName) { case "para": ProcessChildNodes(invalidNodes, newDelta, elem); InsertPara(invalidNodes, newDelta, elem); break; case "verse": state.LastVerseStr = (string)elem.Attribute("number"); InsertVerse(invalidNodes, newDelta, elem, state); break; case "ref": var newRefAttributes = (JObject)attributes?.DeepClone() ?? new JObject(); newRefAttributes.Add(new JProperty(elem.Name.LocalName, GetAttributes(elem))); newRefAttributes = AddInvalidInlineAttribute(invalidNodes, elem, newRefAttributes); newDelta.InsertText(elem.Value, state.CurRef, newRefAttributes); break; case "char": var newChildAttributes = (JObject)attributes?.DeepClone() ?? new JObject(); JToken existingCharAttrs = newChildAttributes["char"]; JObject newCharAttrs = GetAttributes(elem); if (!newCharAttrs.ContainsKey("cid")) { newCharAttrs.Add("cid", GuidService.Generate()); } if (existingCharAttrs == null) { newChildAttributes.Add(new JProperty(elem.Name.LocalName, newCharAttrs)); } else { switch (existingCharAttrs) { case JArray array: array.Add(newCharAttrs); break; case JObject obj: newChildAttributes[elem.Name.LocalName] = new JArray(obj, newCharAttrs); break; } } newChildAttributes = AddInvalidInlineAttribute(invalidNodes, elem, newChildAttributes); if (!elem.Nodes().Any() && elem.Value == "") { newDelta.InsertEmpty(state.CurRef, newChildAttributes); } else { ProcessChildNodes(invalidNodes, newDelta, elem, state, newChildAttributes); } break; case "table": state.TableIndex++; JObject tableAttributes = GetAttributes(elem); tableAttributes.Add(new JProperty("id", $"table_{state.TableIndex}")); int rowIndex = 1; foreach (XElement row in elem.Elements("row")) { var rowAttributes = new JObject( new JProperty("id", $"row_{state.TableIndex}_{rowIndex}")); int cellIndex = 1; foreach (XElement cell in row.Elements()) { state.CurRef = $"cell_{state.TableIndex}_{rowIndex}_{cellIndex}"; ProcessChildNode(invalidNodes, newDelta, cell, state); SegmentEnded(newDelta, state.CurRef); var attrs = new JObject( new JProperty("table", tableAttributes), new JProperty("row", rowAttributes)); if (cell.Name.LocalName == "cell") { attrs.Add(new JProperty("cell", GetAttributes(cell))); } attrs = AddInvalidBlockAttribute(invalidNodes, elem, attrs); attrs = AddInvalidBlockAttribute(invalidNodes, row, attrs); attrs = AddInvalidBlockAttribute(invalidNodes, cell, attrs); newDelta.Insert("\n", attrs); cellIndex++; } rowIndex++; } state.CurRef = null; break; case "cell": ProcessChildNodes(invalidNodes, newDelta, elem, state); break; default: InsertEmbed(invalidNodes, newDelta, elem, state.CurRef, attributes); break; } break; case XText text: newDelta.InsertText(text.Value, state.CurRef, AddInvalidInlineAttribute(invalidNodes, text, attributes)); break; } }
/// <summary> /// Create list of ChapterDelta objects from USX. /// /// PT Data Access gives USX with chapters for each chapter that is /// present in its project content. It will skip over chapters that are /// not present in its project content. If there are no chapters present /// in the project content, PT Data Access will return USX with no explicit /// chapters. /// /// ToChapterDeltas will return a ChapterDelta for each chapter in /// USX. If there are no explicit chapters in USX, return a single /// ChapterDelta with a non-null Delta with an empty Ops list. This /// is because every book has at least one chapter. The book /// introduction is part of an implicit first chapter, even if there /// are no explicit chapters. /// </summary> public IEnumerable <ChapterDelta> ToChapterDeltas(XDocument usxDoc) { var invalidNodes = new HashSet <XNode>(); usxDoc.Validate(Schemas, (o, e) => { XNode node; var attr = o as XAttribute; if (attr != null) { node = attr.Parent; } else { node = (XNode)o; } invalidNodes.Add(node); }, true); var chapterDeltas = new List <ChapterDelta>(); var chapterDelta = new Delta(); bool isChapterValid = true; var nextIds = new Dictionary <string, int>(); var state = new ParseState(); foreach (XNode node in usxDoc.Element("usx").Nodes()) { switch (node) { case XElement elem: switch (elem.Name.LocalName) { case "book": break; case "para": if (state.ImpliedParagraph) { chapterDelta.Insert('\n'); state.ImpliedParagraph = false; } var style = (string)elem.Attribute("style"); bool canContainVerseText = CanParaContainVerseText(style); if (canContainVerseText) { if (state.CurRef != null) { int slashIndex = state.CurRef.IndexOf("/", StringComparison.Ordinal); if (slashIndex != -1) { state.CurRef = state.CurRef.Substring(0, slashIndex); } state.CurRef = GetParagraphRef(nextIds, state.CurRef, state.CurRef + "/" + style); } else { state.CurRef = GetParagraphRef(nextIds, style, style); } } else if (style == "b") { state.CurRef = null; } else { state.CurRef = GetParagraphRef(nextIds, style, style); } ProcessChildNodes(invalidNodes, chapterDelta, elem, state); SegmentEnded(chapterDelta, state.CurRef); if (!canContainVerseText) { state.CurRef = null; } InsertPara(invalidNodes, chapterDelta, elem); break; case "chapter": if (state.CurChapter != null) { ChapterEnded(chapterDeltas, chapterDelta, isChapterValid, state); nextIds.Clear(); chapterDelta = new Delta(); isChapterValid = true; } state.CurRef = null; state.LastVerse = 0; state.CurChapter = (string)elem.Attribute("number"); chapterDelta.InsertEmbed("chapter", GetAttributes(elem), attributes: AddInvalidBlockAttribute(invalidNodes, elem)); break; // according to the USX schema, a verse can only occur within a paragraph, but Paratext 8.0 // can still generate USX with verses at the top-level case "verse": ProcessChildNode(invalidNodes, chapterDelta, elem, state); state.ImpliedParagraph = true; break; default: ProcessChildNode(invalidNodes, chapterDelta, elem, state); break; } if (elem.GetSchemaInfo().Validity != XmlSchemaValidity.Valid) { isChapterValid = false; } break; case XText text: chapterDelta.InsertText(text.Value, state.CurRef, AddInvalidInlineAttribute(invalidNodes, text)); state.ImpliedParagraph = true; break; } } if (state.CurChapter == null) { state.CurChapter = "1"; } ChapterEnded(chapterDeltas, chapterDelta, isChapterValid, state); return(chapterDeltas); }
public static Delta InsertPara(this Delta delta, JObject paraAttributes, JObject attributes = null) { attributes = (JObject)attributes?.DeepClone() ?? new JObject(); attributes.Add(new JProperty("para", paraAttributes)); return(delta.Insert("\n", attributes)); }
public static Delta InsertEmpty(this Delta delta, string segRef, JObject attributes = null) { attributes = (JObject)attributes?.DeepClone() ?? new JObject(); attributes.Add(new JProperty("segment", segRef)); return(delta.Insert(new { empty = true }, attributes)); }
public static Delta InsertChar(this Delta delta, string text, object attributes, string segRef = null) { return(delta.Insert(text, CreateAttributes("char", attributes, segRef))); }
public static Delta InsertPara(this Delta delta, JObject attributes) { var attrs = new JObject(new JProperty("para", attributes)); return(delta.Insert("\n", attrs)); }
public static Delta InsertChapter(this Delta delta, string number, object attributes) { return(delta.Insert(new { chapter = number }, CreateAttributes("chapter", attributes))); }
public IReadOnlyDictionary <int, (Delta Delta, int LastVerse)> ToChapterDeltas(XElement usxElem) { var chapterDeltas = new SortedList <int, (Delta Delta, int LastVerse)>(); var chapterDelta = new Delta(); string lastVerse = null; var nextIds = new Dictionary <string, int>(); string curRef = null; int curChapter = 0; int tableIndex = 0; bool topLevelVerses = false; foreach (XNode node in usxElem.Nodes()) { switch (node) { case XElement elem: switch (elem.Name.LocalName) { case "book": break; case "para": if (topLevelVerses) { // add implicit paragraph when there are top-level verses chapterDelta.Insert('\n'); topLevelVerses = false; } var style = (string)elem.Attribute("style"); bool paraStyle = IsParagraphStyle(style); if (paraStyle) { if (curRef != null) { int slashIndex = curRef.IndexOf("/", StringComparison.Ordinal); if (slashIndex != -1) { curRef = curRef.Substring(0, slashIndex); } curRef = GetParagraphRef(nextIds, curRef, curRef + "/" + style); } } else { curRef = GetParagraphRef(nextIds, style, style); } ProcessChildNodes(chapterDelta, elem, curChapter, ref lastVerse, ref curRef, ref tableIndex); SegmentEnded(chapterDelta, curRef); if (!paraStyle) { curRef = null; } chapterDelta.InsertPara(GetAttributes(elem)); break; case "chapter": if (curChapter != 0) { ChapterEnded(chapterDeltas, chapterDelta, curChapter, lastVerse, curRef, topLevelVerses); chapterDelta = new Delta(); } curRef = null; lastVerse = null; curChapter = (int)elem.Attribute("number"); chapterDelta.InsertEmbed("chapter", GetAttributes(elem)); break; // according to the USX schema, a verse can only occur within a paragraph, but Paratext 8.0 // can still generate USX with verses at the top-level case "verse": ProcessChildNode(chapterDelta, elem, curChapter, ref lastVerse, ref curRef, ref tableIndex); topLevelVerses = true; break; default: ProcessChildNode(chapterDelta, elem, curChapter, ref lastVerse, ref curRef, ref tableIndex); break; } break; case XText text: chapterDelta.InsertText(text.Value, curRef); break; } } ChapterEnded(chapterDeltas, chapterDelta, curChapter, lastVerse, curRef, topLevelVerses); return(chapterDeltas); }
public static Delta InsertVerse(this Delta delta, string number, object attributes) { return(delta.Insert(new { verse = number }, CreateAttributes("verse", attributes))); }
public static Delta InsertBlank(this Delta delta, string segRef) { var attrs = new JObject(new JProperty("segment", segRef)); return(delta.Insert(new { blank = true }, attrs)); }