@@ -39,6 +39,27 @@ func Parse(r io.Reader) (*Node, error) {
39
39
40
40
// ParseWithOptions is like parse, but with custom options
41
41
func ParseWithOptions (r io.Reader , options ParserOptions ) (* Node , error ) {
42
+ var data []byte
43
+ var lineStarts []int
44
+
45
+ // If line numbers are requested, read all data for position tracking
46
+ if options .WithLineNumbers {
47
+ var err error
48
+ data , err = io .ReadAll (r )
49
+ if err != nil {
50
+ return nil , err
51
+ }
52
+ r = bytes .NewReader (data )
53
+
54
+ // Pre-calculate line starts
55
+ lineStarts = []int {0 }
56
+ for i , b := range data {
57
+ if b == '\n' {
58
+ lineStarts = append (lineStarts , i + 1 )
59
+ }
60
+ }
61
+ }
62
+
42
63
p := createParser (r )
43
64
options .apply (p )
44
65
var err error
@@ -62,6 +83,20 @@ func ParseWithOptions(r io.Reader, options ParserOptions) (*Node, error) {
62
83
if ! valid {
63
84
return nil , fmt .Errorf ("xmlquery: invalid XML document" )
64
85
}
86
+
87
+ // If line numbers were requested, annotate the parsed document
88
+ if options .WithLineNumbers {
89
+ annotator := & lineNumberAnnotator {
90
+ data : data ,
91
+ lineStarts : lineStarts ,
92
+ }
93
+
94
+ err = annotator .annotateLineNumbers (p .doc )
95
+ if err != nil {
96
+ return nil , err
97
+ }
98
+ }
99
+
65
100
return p .doc , nil
66
101
}
67
102
@@ -730,45 +765,7 @@ func (p *lineNumberAnnotator) findProcessingInstructionPosition(target string) i
730
765
return 1
731
766
}
732
767
733
- // ParseWithLineNumbers returns the parse tree for the XML from the given Reader with line number annotations.
734
- func ParseWithLineNumbers (r io.Reader ) (* Node , error ) {
735
- return ParseWithLineNumbersAndOptions (r , ParserOptions {})
736
- }
737
768
738
- // ParseWithLineNumbersAndOptions is like ParseWithLineNumbers, but with custom options
739
- func ParseWithLineNumbersAndOptions (r io.Reader , options ParserOptions ) (* Node , error ) {
740
- // Read all data first so we can track positions
741
- data , err := io .ReadAll (r )
742
- if err != nil {
743
- return nil , err
744
- }
745
-
746
- // Parse with the standard parser first
747
- doc , err := ParseWithOptions (bytes .NewReader (data ), options )
748
- if err != nil {
749
- return nil , err
750
- }
751
-
752
- // Now annotate with line numbers using the sophisticated algorithm
753
- parser := & lineNumberAnnotator {
754
- data : data ,
755
- lineStarts : []int {0 },
756
- }
757
-
758
- // Pre-calculate line starts
759
- for i , b := range data {
760
- if b == '\n' {
761
- parser .lineStarts = append (parser .lineStarts , i + 1 )
762
- }
763
- }
764
-
765
- err = parser .annotateLineNumbers (doc )
766
- if err != nil {
767
- return nil , err
768
- }
769
-
770
- return doc , nil
771
- }
772
769
773
770
// LoadURLWithLineNumbers loads the XML document from the specified URL with line number annotations.
774
771
func LoadURLWithLineNumbers (url string ) (* Node , error ) {
@@ -779,7 +776,7 @@ func LoadURLWithLineNumbers(url string) (*Node, error) {
779
776
defer resp .Body .Close ()
780
777
781
778
if xmlMIMERegex .MatchString (resp .Header .Get ("Content-Type" )) {
782
- return ParseWithLineNumbers (resp .Body )
779
+ return ParseWithOptions (resp .Body , ParserOptions { WithLineNumbers : true } )
783
780
}
784
781
return nil , fmt .Errorf ("invalid XML document(%s)" , resp .Header .Get ("Content-Type" ))
785
782
}
0 commit comments