Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        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));
        }
Ejemplo n.º 3
0
 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));
 }
Ejemplo n.º 4
0
        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));
        }
Ejemplo n.º 5
0
        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)));
        }
Ejemplo n.º 6
0
        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));
        }
Ejemplo n.º 7
0
        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));
        }
Ejemplo n.º 8
0
        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));
        }
Ejemplo n.º 9
0
        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));
        }
Ejemplo n.º 10
0
        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;
            }
        }
Ejemplo n.º 11
0
 public static Delta InsertPara(this Delta delta, object attributes)
 {
     return(delta.Insert("\n", CreateAttributes("para", attributes)));
 }
Ejemplo n.º 12
0
        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;
            }
        }
Ejemplo n.º 13
0
        /// <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);
        }
Ejemplo n.º 14
0
 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));
 }
Ejemplo n.º 15
0
 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));
 }
Ejemplo n.º 16
0
 public static Delta InsertChar(this Delta delta, string text, object attributes, string segRef = null)
 {
     return(delta.Insert(text, CreateAttributes("char", attributes, segRef)));
 }
Ejemplo n.º 17
0
        public static Delta InsertPara(this Delta delta, JObject attributes)
        {
            var attrs = new JObject(new JProperty("para", attributes));

            return(delta.Insert("\n", attrs));
        }
Ejemplo n.º 18
0
 public static Delta InsertChapter(this Delta delta, string number, object attributes)
 {
     return(delta.Insert(new { chapter = number }, CreateAttributes("chapter", attributes)));
 }
Ejemplo n.º 19
0
        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);
        }
Ejemplo n.º 20
0
 public static Delta InsertVerse(this Delta delta, string number, object attributes)
 {
     return(delta.Insert(new { verse = number }, CreateAttributes("verse", attributes)));
 }
Ejemplo n.º 21
0
        public static Delta InsertBlank(this Delta delta, string segRef)
        {
            var attrs = new JObject(new JProperty("segment", segRef));

            return(delta.Insert(new { blank = true }, attrs));
        }