Projekt

Obecné

Profil

Stáhnout (24.8 KB) Statistiky
| Větev: | Tag: | Revize:
1
using Core.Entities;
2
using Core.GraphUtils;
3
using Ganss.XSS;
4
using HtmlAgilityPack;
5
using Models.Tags;
6
using System;
7
using System.Collections.Generic;
8
using System.Linq;
9
using System.Text;
10
using System.Threading.Tasks;
11

    
12
namespace Core.Services
13
{
14
    public class HTMLService : IHTMLService
15
    {
16

    
17
        private const string TAG_ID_ATTRIBUTE_NAME = "aswi-tag-id";
18
        private const string TAG_INSTANCE_ATTRIBUTE_NAME = "aswi-tag-instance";
19
        private const string TAG_EF_ID_ATTRIBUTE_NAME = "aswi-tag-ef-id";
20

    
21
        public class CachedInfo
22
        {
23
            public List<int> TagStartPositions = new();
24
            public List<int> TagStartLengths = new();
25
            public List<int> TagClosingPositions = new();
26
            public List<int> TagClosingLengths = new();
27
            public Dictionary<HtmlNode, HtmlNode> NodeDict = new();
28
            public List<TagInstanceCSSInfo> TagInstanceCSS = new();
29
        }
30

    
31
        private List<int> TagStartPositions = new();
32
        private List<int> TagStartLengths = new();
33
        private List<int> TagClosingPositions = new();
34
        private List<int> TagClosingLengths = new();
35
        private Dictionary<HtmlNode, HtmlNode> NodeDict = new();
36
        private List<TagInstanceCSSInfo> TagInstanceCSS = new();
37

    
38
        private void UnpackCachedInfo(CachedInfo cachedInfo)
39
        {
40
            TagStartPositions = cachedInfo.TagStartPositions;
41
            TagStartLengths = cachedInfo.TagStartLengths;
42
            TagClosingPositions = cachedInfo.TagClosingPositions;
43
            TagClosingLengths = cachedInfo.TagClosingLengths;
44
            NodeDict = cachedInfo.NodeDict;
45
            TagInstanceCSS = cachedInfo.TagInstanceCSS;
46
        }
47

    
48

    
49
        /*
50
         *      Full HTML Preprocessing -------------------------------------------------------------------------------
51
         */
52

    
53
        public (string, CachedInfo) FullPreprocessHTML(string htmlSource, List<AnnotationTagGeneric> tags)
54
        {
55
            var docOriginal = new HtmlDocument();
56
            docOriginal.LoadHtml(htmlSource);
57
            var docToEdit = new HtmlDocument();
58
            docToEdit.LoadHtml(htmlSource);
59

    
60
            var descendantsOriginal = docOriginal.DocumentNode.DescendantsAndSelf();
61
            var descendantsToEdit = docToEdit.DocumentNode.DescendantsAndSelf().ToList();
62

    
63
            int currentId = 0;
64

    
65
            FillNodeDict(descendantsOriginal, descendantsToEdit);
66
            AssignIdsToOriginalDocument(descendantsOriginal, ref currentId);
67

    
68
            WrapTextInSpan(descendantsOriginal, docToEdit);
69

    
70
            descendantsToEdit = docToEdit.DocumentNode.DescendantsAndSelf().ToList();
71
            int descCount = descendantsToEdit.Count;
72

    
73
            foreach (var tag in tags)
74
            {
75
                int i = 0;
76
                List<HtmlNode> addedForSelection = new();
77
                while (i < descCount)
78
                {
79
                    for (; i < descCount; i++)
80
                    {
81
                        var node = descendantsToEdit.ElementAt(i);
82
                        if (!node.Name.Contains("#text") || addedForSelection.Contains(node) || addedForSelection.Contains(node.ParentNode) || node.ParentNode.Name == "style")
83
                        {
84
                            continue;
85
                        }
86

    
87
                        int nodeId = node.ParentNode.GetAttributeValue(TAG_ID_ATTRIBUTE_NAME, -1);
88

    
89
                        var start = TagStartPositions[nodeId] + TagStartLengths[nodeId];
90
                        var end = TagClosingPositions[nodeId];
91

    
92
                        int selectionStart = tag.Position;
93
                        int selectionEnd = tag.Position + tag.Length;
94

    
95
                        if (selectionStart < end && selectionEnd > start)
96
                        {
97
                            if (selectionStart <= start && selectionEnd >= end)
98
                            {
99
                                addedForSelection.Add(SolveFullFill(node, selectionStart, selectionEnd, start, end, docToEdit, tag));
100
                            }
101
                            else if (selectionStart <= start)
102
                            {
103
                                addedForSelection.AddRange(SolveRightGap(node, selectionStart, selectionEnd, start, end, docToEdit, tag));
104
                            }
105
                            else if (selectionEnd >= end)
106
                            {
107
                                addedForSelection.AddRange(SolveLeftGap(node, selectionStart, selectionEnd, start, end, docToEdit, tag));
108
                            }
109
                            else
110
                            {
111
                                addedForSelection.AddRange(SolveLeftRightGap(node, selectionStart, selectionEnd, start, end, docToEdit, tag));
112
                            }
113
                            descendantsToEdit = docToEdit.DocumentNode.DescendantsAndSelf().ToList();
114
                            descCount = descendantsToEdit.Count;
115
                            break;
116
                        }
117
                    }
118
                }
119

    
120
            }
121

    
122
            ModifyLinks(descendantsToEdit);
123
            string docToRender = docToEdit.DocumentNode.OuterHtml;
124
            HtmlSanitizer sanitizer = new HtmlSanitizer();
125
            sanitizer.AllowedAttributes.Clear();
126
            sanitizer.AllowedAttributes.Add(TAG_ID_ATTRIBUTE_NAME);
127
            sanitizer.AllowedAttributes.Add(TAG_INSTANCE_ATTRIBUTE_NAME);
128
            sanitizer.AllowedAttributes.Add(TAG_EF_ID_ATTRIBUTE_NAME);
129
            sanitizer.AllowedAttributes.Add("href");
130
            sanitizer.AllowedAttributes.Add("end");
131
            sanitizer.AllowedAttributes.Add("start");
132
            sanitizer.AllowedAttributes.Add("class");
133
            sanitizer.AllowedAttributes.Add("target");
134
            sanitizer.AllowedAttributes.Add("id");
135
            if (sanitizer.AllowedTags.Contains("script"))
136
            {
137
                sanitizer.AllowedTags.Remove("script");
138
            }
139
            if (!sanitizer.AllowedTags.Contains("style"))
140
            {
141
                sanitizer.AllowedTags.Add("style");
142
            }
143
            sanitizer.AllowedTags.Add("a");
144
            docToRender = sanitizer.Sanitize(docToRender);
145
            docToRender = docToRender.Replace("&nbsp;", " ");
146
            GenerateCSS(tags);
147

    
148
            return (docToRender, new CachedInfo()
149
            {
150
                TagStartPositions = TagStartPositions,
151
                TagClosingPositions = TagClosingPositions,
152
                TagStartLengths = TagStartLengths,
153
                TagClosingLengths = TagClosingLengths,
154
                TagInstanceCSS = TagInstanceCSS,
155
                NodeDict = NodeDict
156
            });
157
        }
158

    
159
        private HtmlNode SolveFullFill(HtmlNode node, int selectionStart, int selectionEnd, int start, int end, HtmlDocument docToEdit, AnnotationTagGeneric tag)
160
        {
161
            // full fill
162
            string textSelected = node.InnerText;
163

    
164
            var parentNode = node.ParentNode;
165
            int nodeIndex = parentNode.ChildNodes.IndexOf(node);
166
            parentNode.ChildNodes.RemoveAt(nodeIndex);
167

    
168
            EPosition markerPosition = EPosition.MARK_NONE;
169
            if (selectionEnd == end && selectionStart == start)
170
            {
171
                markerPosition = EPosition.MARK_LEFT_RIGHT;
172
            }
173

    
174
            HtmlNode spanSelected = CreateSpan(docToEdit, textSelected, TagStartPositions.Count, tag.Instance, tag.Id, start, markerPosition);
175
            parentNode.ChildNodes.Insert(nodeIndex, spanSelected);
176

    
177
            return spanSelected;
178
        }
179

    
180
        private List<HtmlNode> SolveRightGap(HtmlNode node, int selectionStart, int selectionEnd, int start, int end, HtmlDocument docToEdit,
181
                                             AnnotationTagGeneric tag)
182
        {
183
            // partial fill, end gap
184
            string text = node.InnerText;
185
            string textAfter = text.Substring(Math.Min(selectionStart - start + tag.Length, text.Length));
186
            string textSelected = text.Substring(0, selectionEnd - start);
187

    
188
            var parentNode = node.ParentNode;
189
            int nodeIndex = parentNode.ChildNodes.IndexOf(node);
190
            parentNode.ChildNodes.RemoveAt(nodeIndex);
191

    
192
            int spanSelectedStart = start;
193
            int spanAfterStart = start + textSelected.Length;
194

    
195
            HtmlNode spanSelected = CreateSpan(docToEdit, textSelected, TagStartPositions.Count, tag.Instance, tag.Id, spanSelectedStart, EPosition.MARK_RIGHT);
196
            parentNode.ChildNodes.Insert(nodeIndex, spanSelected);
197

    
198
            HtmlNode spanAfter = CreateSpan(docToEdit, textAfter, TagStartPositions.Count, null, null, spanAfterStart);
199
            parentNode.ChildNodes.Insert(nodeIndex + 1, spanAfter);
200

    
201
            return new() { spanSelected, spanAfter };
202
        }
203

    
204
        private List<HtmlNode> SolveLeftGap(HtmlNode node, int selectionStart, int selectionEnd, int start, int end, HtmlDocument docToEdit,
205
                                             AnnotationTagGeneric tag)
206
        {
207
            // partial fill, start gap
208
            string text = node.InnerText;
209
            string textBefore = text.Substring(0, selectionStart - start);
210
            string textSelected = text.Substring(selectionStart - start, Math.Min(tag.Length, text.Length - textBefore.Length));
211

    
212
            var parentNode = node.ParentNode;
213
            int nodeIndex = parentNode.ChildNodes.IndexOf(node);
214
            parentNode.ChildNodes.RemoveAt(nodeIndex);
215

    
216
            int spanBeforeStart = start;
217
            int spanSelectedStart = start + textBefore.Length;
218

    
219
            HtmlNode spanBefore = CreateSpan(docToEdit, textBefore, TagStartPositions.Count, null, null, spanBeforeStart);
220
            parentNode.ChildNodes.Insert(nodeIndex, spanBefore);
221

    
222
            HtmlNode spanSelected = CreateSpan(docToEdit, textSelected, TagStartPositions.Count, tag.Instance, tag.Id, spanSelectedStart, EPosition.MARK_LEFT);
223
            parentNode.ChildNodes.Insert(nodeIndex + 1, spanSelected);
224

    
225
            return new() { spanSelected, spanBefore };
226
        }
227

    
228
        private List<HtmlNode> SolveLeftRightGap(HtmlNode node, int selectionStart, int selectionEnd, int start, int end, HtmlDocument docToEdit,
229
                                                 AnnotationTagGeneric tag)
230
        {
231
            // partial fill, start gap end gap
232
            string text = node.InnerText;
233
            string textBefore = text.Substring(0, selectionStart - start);
234
            string textAfter = text.Substring(selectionStart - start + tag.Length);
235
            string textSelected = text.Substring(selectionStart - start, tag.Length);
236

    
237
            var parentNode = node.ParentNode;
238
            int nodeIndex = parentNode.ChildNodes.IndexOf(node);
239
            parentNode.ChildNodes.RemoveAt(nodeIndex);
240

    
241
            int spanBeforeStart = start;
242
            int spanSelectedStart = start + textBefore.Length;
243
            int spanAfterStart = start + textBefore.Length + textSelected.Length;
244

    
245
            HtmlNode spanBefore = CreateSpan(docToEdit, textBefore, TagStartPositions.Count, null, null, spanBeforeStart);
246
            parentNode.ChildNodes.Insert(nodeIndex, spanBefore);
247

    
248
            HtmlNode spanSelected = CreateSpan(docToEdit, textSelected, TagStartPositions.Count, tag.Instance, tag.Id, spanSelectedStart, EPosition.MARK_LEFT_RIGHT);
249
            parentNode.ChildNodes.Insert(nodeIndex + 1, spanSelected);
250

    
251
            HtmlNode spanAfter = CreateSpan(docToEdit, textAfter, TagStartPositions.Count, null, null, spanAfterStart);
252
            parentNode.ChildNodes.Insert(nodeIndex + 2, spanAfter);
253

    
254
            return new() { spanSelected, spanBefore, spanAfter };
255
        }
256

    
257
        private HtmlNode CreateSpan(HtmlDocument doc, string text, int tagId, Guid? instanceId, Guid? entityId, int startPosition, EPosition position = EPosition.MARK_NONE)
258
        {
259
            HtmlNode span = doc.CreateElement("span");
260
            span.InnerHtml = text;
261
            TagStartPositions.Add(startPosition);
262
            TagStartLengths.Add(0);
263
            TagClosingPositions.Add(startPosition + text.Length);
264
            TagClosingLengths.Add(0);
265
            span.Attributes.Add(TAG_ID_ATTRIBUTE_NAME, tagId.ToString());
266

    
267
            if (instanceId != null)
268
            {
269
                span.AddClass("annotation");
270
                span.Attributes.Add(TAG_INSTANCE_ATTRIBUTE_NAME, instanceId.Value.ToString());
271
                span.Attributes.Add(TAG_EF_ID_ATTRIBUTE_NAME, entityId.ToString());
272
                span.Attributes.Add("id", entityId.ToString());
273

    
274
                if (position == EPosition.MARK_LEFT || position == EPosition.MARK_LEFT_RIGHT)
275
                {
276
                    span.Attributes.Add("start", "1");
277
                }
278
                if (position == EPosition.MARK_RIGHT || position == EPosition.MARK_LEFT_RIGHT)
279
                {
280
                    span.Attributes.Add("end", "1");
281
                }
282
            }
283

    
284
            return span;
285
        }
286

    
287
        private enum EPosition
288
        {
289
            MARK_LEFT = 5,
290
            MARK_RIGHT = 3,
291
            MARK_LEFT_RIGHT = 2,
292
            MARK_NONE = 0
293
        }
294

    
295
        private void ModifyLinks(IEnumerable<HtmlNode> descendantsOriginal)
296
        {
297
            foreach (var descendant in descendantsOriginal)
298
            {
299
                if (descendant.Name == "a")
300
                {
301
                    if (descendant.Attributes.Contains("href"))
302
                    {
303
                        descendant.SetAttributeValue("href", "/link?url=" + descendant.Attributes["href"].Value);
304
                        descendant.SetAttributeValue("target", "_blank");
305
                    }
306
                }
307
            }
308
        }
309

    
310
        private void WrapTextInSpan(IEnumerable<HtmlNode> descendantsOriginal, HtmlDocument docToEdit)
311
        {
312
            // Special case for non-html documents
313
            if (descendantsOriginal.Count() == 2)
314
            {
315
                var documentNode = descendantsOriginal.ElementAt(0);
316
                var childNode = descendantsOriginal.ElementAt(1);
317
                if (documentNode.Name == "#document" && childNode.Name == "#text")
318
                {
319
                    HtmlNode coveringSpan = docToEdit.CreateElement("span");
320
                    coveringSpan.InnerHtml = childNode.InnerHtml;
321
                    TagStartPositions.Add(childNode.InnerStartIndex);
322
                    TagStartLengths.Add(0);
323
                    TagClosingPositions.Add(childNode.InnerStartIndex + childNode.InnerLength);
324
                    TagClosingLengths.Add(0);
325
                    coveringSpan.Attributes.Add(TAG_ID_ATTRIBUTE_NAME, (TagStartPositions.Count - 1).ToString());
326

    
327
                    var parent = NodeDict[documentNode];
328

    
329
                    parent.ChildNodes.RemoveAt(0);
330
                    parent.ChildNodes.Add(coveringSpan);
331

    
332
                    return;
333
                }
334
            }
335

    
336
            foreach (var node in descendantsOriginal)
337
            {
338
                var originalNode = node;
339
                var toEditNode = NodeDict[node];
340

    
341
                if (originalNode.Name.Contains("#"))
342
                {
343
                    continue;
344
                }
345
                else
346
                {
347
                    bool onlyText = true;
348
                    bool onlySubtags = true;
349

    
350
                    foreach (var child in node.ChildNodes)
351
                    {
352
                        if (child.Name.Contains("#"))
353
                        {
354
                            onlySubtags = false;
355
                        }
356
                        else
357
                        {
358
                            onlyText = false;
359
                        }
360
                    }
361

    
362
                    if (onlyText || onlySubtags)
363
                    {
364
                        continue;
365
                    }
366
                    else
367
                    {
368

    
369
                        foreach (var child in node.ChildNodes)
370
                        {
371
                            if (child.Name.Contains("#text"))
372
                            {
373
                                HtmlNode coveringSpan = docToEdit.CreateElement("span");
374
                                coveringSpan.InnerHtml = child.InnerHtml;
375
                                TagStartPositions.Add(child.InnerStartIndex);
376
                                TagStartLengths.Add(0);
377
                                TagClosingPositions.Add(child.InnerStartIndex + child.InnerLength);
378
                                TagClosingLengths.Add(0);
379
                                coveringSpan.Attributes.Add(TAG_ID_ATTRIBUTE_NAME, (TagStartPositions.Count - 1).ToString());
380

    
381
                                var parent = NodeDict[node];
382
                                var index = parent.ChildNodes.IndexOf(NodeDict[child]);
383

    
384
                                parent.ChildNodes.RemoveAt(index);
385
                                parent.ChildNodes.Insert(index, coveringSpan);
386
                            }
387
                        }
388
                    }
389
                }
390
            }
391
        }
392

    
393
        private void GenerateCSS(List<AnnotationTagGeneric> tags)
394
        {
395
            /*string inner = "span.annotation {border-bottom: 2px solid;}";
396
            inner += "span {line-height: 30px}\n";*/
397

    
398
            var tagPaddingDict = Intersections.ColorGraph(Intersections.FindIntersections(tags));
399
            foreach (var tag in tags.DistinctBy(t => t.Instance))
400
            {
401
                var padding = (tagPaddingDict[tag] + 2) * 2;
402
                TagInstanceCSS.Add(new()
403
                {
404
                    InstanceId = tag.Instance,
405
                    Color = tag.Tag.Color,
406
                    Padding = padding
407
                });
408
            }
409
        }
410

    
411
        private void AssignIdsToOriginalDocument(IEnumerable<HtmlNode> descendantsOriginal, ref int currentId)
412
        {
413
            foreach (var node in descendantsOriginal)
414
            {
415
                var originalNode = node;
416
                var toEditNode = NodeDict[node];
417

    
418
                if (originalNode.Name.Contains("#"))
419
                {
420
                    continue;
421
                }
422
                else
423
                {
424
                    TagStartPositions.Add(originalNode.OuterStartIndex);
425
                    TagStartLengths.Add(originalNode.InnerStartIndex - originalNode.OuterStartIndex);
426
                    currentId = TagStartPositions.Count - 1;
427
                    toEditNode.Attributes.Add(TAG_ID_ATTRIBUTE_NAME, currentId.ToString());
428

    
429
                    TagClosingPositions.Add(originalNode.InnerStartIndex + originalNode.InnerLength);
430
                    TagClosingLengths.Add((originalNode.OuterStartIndex + originalNode.OuterLength) - (originalNode.InnerStartIndex + originalNode.InnerLength));
431
                }
432
            }
433
        }
434

    
435
        private void FillNodeDict(IEnumerable<HtmlNode> descendantsOriginal, IEnumerable<HtmlNode> descendantsToEdit)
436
        {
437
            var zipped = descendantsOriginal.Zip(descendantsToEdit, (orig, toEdit) => new
438
            {
439
                Original = orig,
440
                ToEdit = toEdit
441
            });
442
            foreach (var node in zipped)
443
            {
444
                var originalNode = node.Original;
445
                var toEditNode = node.ToEdit;
446
                NodeDict.Add(originalNode, toEditNode);
447
            }
448
        }
449

    
450

    
451
        /*
452
         *      Full HTML Preprocessing -------------------------------------------------------------------------------
453
         */
454

    
455
        /*
456
         *      Partial HTML Preprocessing ----------------------------------------------------------------------------
457
         */
458

    
459
        public (string, CachedInfo) PartialPreprocessHTMLAddTag(string htmlToEdit, string htmlOriginal, AnnotationTagGeneric tagToAdd, List<AnnotationTagGeneric> tags, CachedInfo cachedInfo)
460
        {
461
            UnpackCachedInfo(cachedInfo);
462

    
463
            var docOriginal = new HtmlDocument();
464
            docOriginal.LoadHtml(htmlOriginal);
465
            var docToEdit = new HtmlDocument();
466
            docToEdit.LoadHtml(htmlToEdit);
467

    
468
            var descendantsToEdit = docToEdit.DocumentNode.DescendantsAndSelf().ToList();
469

    
470
            int i = 0;
471
            List<HtmlNode> addedForSelection = new();
472

    
473
            int descendantsCount = descendantsToEdit.Count();
474
            while (i < descendantsCount)
475
            {
476
                for (; i < descendantsCount; i++)
477
                {
478
                    var node = descendantsToEdit.ElementAt(i);
479
                    if (!node.Name.Contains("#text") || addedForSelection.Contains(node) || addedForSelection.Contains(node.ParentNode) ||
480
                        node.ParentNode.Name == "style" || node.ParentNode.Name.StartsWith("#"))
481
                    {
482
                        continue;
483
                    }
484

    
485
                    int nodeId = node.ParentNode.GetAttributeValue(TAG_ID_ATTRIBUTE_NAME, -1);
486

    
487
                    var start = TagStartPositions[nodeId] + TagStartLengths[nodeId];
488
                    var end = TagClosingPositions[nodeId];
489

    
490
                    int selectionStart = tagToAdd.Position;
491
                    int selectionEnd = tagToAdd.Position + tagToAdd.Length;
492

    
493
                    if (selectionStart < end && selectionEnd > start)
494
                    {
495
                        if (selectionStart <= start && selectionEnd >= end)
496
                        {
497
                            addedForSelection.Add(SolveFullFill(node, selectionStart, selectionEnd, start, end, docToEdit, tagToAdd));
498
                        }
499
                        else if (selectionStart <= start)
500
                        {
501
                            addedForSelection.AddRange(SolveRightGap(node, selectionStart, selectionEnd, start, end, docToEdit, tagToAdd));
502
                        }
503
                        else if (selectionEnd >= end)
504
                        {
505
                            addedForSelection.AddRange(SolveLeftGap(node, selectionStart, selectionEnd, start, end, docToEdit, tagToAdd));
506
                        }
507
                        else
508
                        {
509
                            addedForSelection.AddRange(SolveLeftRightGap(node, selectionStart, selectionEnd, start, end, docToEdit, tagToAdd));
510
                        }
511
                        descendantsToEdit = docToEdit.DocumentNode.DescendantsAndSelf().ToList();
512
                        descendantsCount = descendantsToEdit.Count();
513
                        break;
514
                    }
515
                }
516
            }
517

    
518
            GenerateCSS(tags);
519
            return (docToEdit.DocumentNode.OuterHtml, new()
520
            {
521
                TagStartPositions = TagStartPositions,
522
                TagStartLengths = TagStartLengths,
523
                TagClosingPositions = TagClosingPositions,
524
                TagClosingLengths = TagClosingLengths,
525
                TagInstanceCSS = TagInstanceCSS,
526
                NodeDict = NodeDict
527
            });
528
        }
529

    
530

    
531
        public (string, CachedInfo) PartialPreprocessHTMLRemoveTag(string htmlToEdit, string htmlOriginal, AnnotationTagGeneric tagToRemove, List<AnnotationTagGeneric> tags, CachedInfo cachedInfo)
532
        {
533
            UnpackCachedInfo(cachedInfo);
534

    
535
            var docOriginal = new HtmlDocument();
536
            docOriginal.LoadHtml(htmlOriginal);
537
            var docToEdit = new HtmlDocument();
538
            docToEdit.LoadHtml(htmlToEdit);
539

    
540
            var descendantsToEdit = docToEdit.DocumentNode.DescendantsAndSelf().ToList();
541

    
542
            int i = 0;
543
            int descendantsCount = descendantsToEdit.Count();
544
            while (i < descendantsCount)
545
            {
546
                for (; i < descendantsCount; i++)
547
                {
548
                    var node = descendantsToEdit.ElementAt(i);
549
                    if (!node.Attributes.Contains(TAG_EF_ID_ATTRIBUTE_NAME))
550
                    {
551
                        continue;
552
                    }
553
                    else
554
                    {
555
                        if (node.Attributes[TAG_EF_ID_ATTRIBUTE_NAME].Value != tagToRemove.Id.ToString())
556
                        {
557
                            continue;
558
                        }
559

    
560
                        node.Attributes.Remove(TAG_EF_ID_ATTRIBUTE_NAME);
561
                        node.Attributes.Remove(TAG_INSTANCE_ATTRIBUTE_NAME);
562
                        node.Attributes.Remove("class");
563
                        node.Attributes.Remove("start");
564
                        node.Attributes.Remove("end");
565

    
566
                        descendantsToEdit = docToEdit.DocumentNode.DescendantsAndSelf().ToList();
567
                        descendantsCount = descendantsToEdit.Count();
568
                        break;
569
                    }
570
                }
571
            }
572

    
573
            GenerateCSS(tags);
574
            return (docToEdit.DocumentNode.OuterHtml, new()
575
            {
576
                TagStartPositions = TagStartPositions,
577
                TagStartLengths = TagStartLengths,
578
                TagClosingPositions = TagClosingPositions,
579
                TagClosingLengths = TagClosingLengths,
580
                TagInstanceCSS = TagInstanceCSS,
581
                NodeDict = NodeDict
582
            });
583
        }
584

    
585
        /*
586
         *      Partial HTML Preprocessing ----------------------------------------------------------------------------
587
         */
588
    }
589
}
(1-1/2)