private XmlApparatusVarContent ParseVariantContent(XElement variant)
        {
            XmlApparatusVarContent content = new XmlApparatusVarContent
            {
                Logger = Logger
            };

            // scan children elements
            foreach (XElement child in variant.Elements())
            {
                switch (child.Name.LocalName)
                {
                case "ident":
                    content.AddIdent(child);
                    break;

                case "add":
                case "note":
                    content.AddAnnotation(child);
                    break;

                default:
                    Logger?.LogError("Unexpected element in variant content:" +
                                     " {ElementName}", child.Name);
                    break;
                }
            }

            // get direct text
            StringBuilder sb = new StringBuilder();

            foreach (XText txt in variant.Nodes().OfType <XText>())
            {
                sb.Append(txt.Value);
            }
            if (sb.Length > 0)
            {
                content.Value = sb.ToString();
            }

            return(content);
        }
        private void AddContentToEntry(XmlApparatusVarContent content,
                                       ApparatusEntry entry)
        {
            // value
            if (!string.IsNullOrWhiteSpace(content.Value))
            {
                entry.Value = content.Value.Trim();
            }

            // ident's
            if (content.Idents.Count > 0)
            {
                entry.NormValue = string.Join(" ", content.Idents);
            }

            // notes
            if (content.Notes.Count > 0)
            {
                // corner case: only note section 1
                if (content.Notes.Count == 1 &&
                    content.Notes[0].SectionId == 1 &&
                    content.Notes[0].Target == null)
                {
                    entry.Note = ApplyMarkdown(content.Notes[0].Value);
                    return;
                }

                // first process wit/source notes, grouped by target
                foreach (var group in from n in content.Notes
                         where n.Target != null
                         group n by n.Target into g
                         select g)
                {
                    ApparatusAnnotatedValue target =
                        entry.Witnesses.Find(w => w.Value == group.Key);
                    if (target != null)
                    {
                        AddNoteToWitOrSource(group.ToList(), target);
                        continue;
                    }
                    target = entry.Authors.Find(a => a.Value == group.Key);
                    if (target != null)
                    {
                        AddNoteToWitOrSource(group.ToList(), target);
                    }
                    else
                    {
                        Logger?.LogError($"Target \"{group.Key}\" not found");
                    }
                }

                // then process untargeted notes
                StringBuilder sb       = new StringBuilder();
                int           curSect  = 1;
                HashSet <int> sections = new HashSet <int>();

                foreach (XmlApparatusNote note in content.Notes
                         .Where(n => n.Target == null)
                         .OrderBy(n => n.SectionId))
                {
                    if (sections.Contains(note.SectionId))
                    {
                        Logger?.LogError(
                            $"Note section {note.SectionId} overwritten by \"{note.Value}\"");
                    }
                    while (curSect < note.SectionId)
                    {
                        sb.Append(NOTE_SECT_SEP);
                        curSect++;
                    }
                    sb.Append(note.Value);
                    sections.Add(note.SectionId);
                }

                if (sb.Length > 0)
                {
                    entry.Note = ApplyMarkdown(sb.ToString());
                }
            }
        }