@@ -29,8 +29,11 @@ export default function readDocType(xmlData, i){
29
29
}
30
30
else if ( hasBody && isElement ( xmlData , i ) ) i += 8 ; //Not supported
31
31
else if ( hasBody && isAttlist ( xmlData , i ) ) i += 8 ; //Not supported
32
- else if ( hasBody && isNotation ( xmlData , i ) ) i += 9 ; //Not supported
33
- else if ( isComment ) comment = true ;
32
+ else if ( hasBody && isNotation ( xmlData , i ) ) {
33
+ i += 9 ; //Not supported
34
+ const { name, publicIdentifier, systemIdentifier, index} = readNotationExp ( xmlData , i + 1 ) ;
35
+ i = index ;
36
+ } else if ( isComment ) comment = true ;
34
37
else throw new Error ( "Invalid DOCTYPE" ) ;
35
38
36
39
angleBracketsCount ++ ;
@@ -124,6 +127,80 @@ function readEntityExp(xmlData, i) {
124
127
return [ entityName , entityValue , i ] ;
125
128
}
126
129
130
+ function readNotationExp ( xmlData , i ) {
131
+ // Skip leading whitespace after <!NOTATION
132
+ i = skipWhitespace ( xmlData , i ) ;
133
+
134
+ // Read notation name
135
+ let notationName = "" ;
136
+ while ( i < xmlData . length && ! / \s / . test ( xmlData [ i ] ) ) {
137
+ notationName += xmlData [ i ] ;
138
+ i ++ ;
139
+ }
140
+
141
+ // Validate notation name
142
+ if ( ! validateEntityName ( notationName ) ) {
143
+ throw new Error ( `Invalid notation name: "${ notationName } "` ) ;
144
+ }
145
+
146
+ // Skip whitespace after notation name
147
+ i = skipWhitespace ( xmlData , i ) ;
148
+
149
+ // Check identifier type (SYSTEM or PUBLIC)
150
+ const identifierType = xmlData . substring ( i , i + 6 ) . toUpperCase ( ) ;
151
+ if ( identifierType !== "SYSTEM" && identifierType !== "PUBLIC" ) {
152
+ throw new Error ( `Expected SYSTEM or PUBLIC, found "${ identifierType } "` ) ;
153
+ }
154
+ i += identifierType . length ;
155
+
156
+ // Skip whitespace after identifier type
157
+ i = skipWhitespace ( xmlData , i ) ;
158
+
159
+ // Read public identifier (if PUBLIC)
160
+ let publicIdentifier = null ;
161
+ let systemIdentifier = null ;
162
+
163
+ if ( identifierType === "PUBLIC" ) {
164
+ [ i , publicIdentifier ] = readIdentifierVal ( xmlData , i ) ;
165
+
166
+ // Skip whitespace after public identifier
167
+ i = skipWhitespace ( xmlData , i ) ;
168
+
169
+ // Optionally read system identifier
170
+ if ( xmlData [ i ] === '"' || xmlData [ i ] === "'" ) {
171
+ [ i , systemIdentifier ] = readIdentifierVal ( xmlData , i ) ;
172
+ }
173
+ } else if ( identifierType === "SYSTEM" ) {
174
+ // Read system identifier (mandatory for SYSTEM)
175
+ [ i , systemIdentifier ] = readIdentifierVal ( xmlData , i ) ;
176
+
177
+ if ( ! systemIdentifier ) {
178
+ throw new Error ( "Missing mandatory system identifier for SYSTEM notation" ) ;
179
+ }
180
+ }
181
+
182
+ return { notationName, publicIdentifier, systemIdentifier, index : -- i } ;
183
+ }
184
+
185
+ function readIdentifierVal ( xmlData , i ) {
186
+ let identifierVal = "" ;
187
+ const startChar = xmlData [ i ] ;
188
+ if ( startChar !== '"' && startChar !== "'" ) {
189
+ throw new Error ( `Expected quoted string, found "${ startChar } "` ) ;
190
+ }
191
+ i ++ ;
192
+
193
+ while ( i < xmlData . length && xmlData [ i ] !== startChar ) {
194
+ identifierVal += xmlData [ i ] ;
195
+ i ++ ;
196
+ }
197
+
198
+ if ( xmlData [ i ] !== startChar ) {
199
+ throw new Error ( "Unterminated identifier" ) ;
200
+ }
201
+ i ++ ;
202
+ return [ i , identifierVal ] ;
203
+ }
127
204
128
205
function isComment ( xmlData , i ) {
129
206
if ( xmlData [ i + 1 ] === '!' &&
0 commit comments