@@ -27,14 +27,20 @@ export default function readDocType(xmlData, i){
2727 val : val
2828 } ;
2929 }
30- else if ( hasBody && isElement ( xmlData , i ) ) i += 8 ; //Not supported
31- else if ( hasBody && isAttlist ( xmlData , i ) ) i += 8 ; //Not supported
32- else if ( hasBody && isNotation ( xmlData , i ) ) {
30+ else if ( hasBody && isElement ( xmlData , i ) ) {
31+ i += 8 ; //Not supported
32+ const { index} = readElementExp ( xmlData , i + 1 ) ;
33+ i = index ;
34+ } else if ( hasBody && isAttlist ( xmlData , i ) ) {
35+ i += 8 ; //Not supported
36+ // const {index} = readAttlistExp(xmlData,i+1);
37+ // i = index;
38+ } else if ( hasBody && isNotation ( xmlData , i ) ) {
3339 i += 9 ; //Not supported
34- const { name , publicIdentifier , systemIdentifier , index} = readNotationExp ( xmlData , i + 1 ) ;
40+ const { index} = readNotationExp ( xmlData , i + 1 ) ;
3541 i = index ;
36- } else if ( isComment ) comment = true ;
37- else throw new Error ( "Invalid DOCTYPE" ) ;
42+ } else if ( isComment ) comment = true ;
43+ else throw new Error ( "Invalid DOCTYPE" ) ;
3844
3945 angleBracketsCount ++ ;
4046 exp = "" ;
@@ -181,6 +187,167 @@ function readIdentifierVal(xmlData, i, type) {
181187 return [ i , identifierVal ] ;
182188}
183189
190+ function readElementExp ( xmlData , i ) {
191+ // <!ELEMENT name (content-model)>
192+
193+ // Skip leading whitespace after <!ELEMENT
194+ i = skipWhitespace ( xmlData , i ) ;
195+
196+ // Read element name
197+ let elementName = "" ;
198+ while ( i < xmlData . length && ! / \s / . test ( xmlData [ i ] ) ) {
199+ elementName += xmlData [ i ] ;
200+ i ++ ;
201+ }
202+
203+ // Validate element name
204+ if ( ! validateEntityName ( elementName ) ) {
205+ throw new Error ( `Invalid element name: "${ elementName } "` ) ;
206+ }
207+
208+ // Skip whitespace after element name
209+ i = skipWhitespace ( xmlData , i ) ;
210+
211+ // Expect '(' to start content model
212+ if ( xmlData [ i ] !== "(" ) {
213+ throw new Error ( `Expected '(', found "${ xmlData [ i ] } "` ) ;
214+ }
215+ i ++ ; // Move past '('
216+
217+ // Read content model
218+ let contentModel = "" ;
219+ while ( i < xmlData . length && xmlData [ i ] !== ")" ) {
220+ contentModel += xmlData [ i ] ;
221+ i ++ ;
222+ }
223+
224+ if ( xmlData [ i ] !== ")" ) {
225+ throw new Error ( "Unterminated content model" ) ;
226+ }
227+
228+ return {
229+ elementName,
230+ contentModel : contentModel . trim ( ) ,
231+ index : i
232+ } ;
233+ }
234+
235+ function readAttlistExp ( xmlData , i ) {
236+ // Skip leading whitespace after <!ATTLIST
237+ i = skipWhitespace ( xmlData , i ) ;
238+
239+ // Read element name
240+ let elementName = "" ;
241+ while ( i < xmlData . length && ! / \s / . test ( xmlData [ i ] ) ) {
242+ elementName += xmlData [ i ] ;
243+ i ++ ;
244+ }
245+
246+ // Validate element name
247+ validateEntityName ( elementName )
248+
249+ // Skip whitespace after element name
250+ i = skipWhitespace ( xmlData , i ) ;
251+
252+ // Read attribute name
253+ let attributeName = "" ;
254+ while ( i < xmlData . length && ! / \s / . test ( xmlData [ i ] ) ) {
255+ attributeName += xmlData [ i ] ;
256+ i ++ ;
257+ }
258+
259+ // Validate attribute name
260+ if ( ! validateEntityName ( attributeName ) ) {
261+ throw new Error ( `Invalid attribute name: "${ attributeName } "` ) ;
262+ }
263+
264+ // Skip whitespace after attribute name
265+ i = skipWhitespace ( xmlData , i ) ;
266+
267+ // Read attribute type
268+ let attributeType = "" ;
269+ if ( xmlData . substring ( i , i + 8 ) . toUpperCase ( ) === "NOTATION" ) {
270+ attributeType = "NOTATION" ;
271+ i += 8 ; // Move past "NOTATION"
272+
273+ // Skip whitespace after "NOTATION"
274+ i = skipWhitespace ( xmlData , i ) ;
275+
276+ // Expect '(' to start the list of notations
277+ if ( xmlData [ i ] !== "(" ) {
278+ throw new Error ( `Expected '(', found "${ xmlData [ i ] } "` ) ;
279+ }
280+ i ++ ; // Move past '('
281+
282+ // Read the list of allowed notations
283+ let allowedNotations = [ ] ;
284+ while ( i < xmlData . length && xmlData [ i ] !== ")" ) {
285+ let notation = "" ;
286+ while ( i < xmlData . length && xmlData [ i ] !== "|" && xmlData [ i ] !== ")" ) {
287+ notation += xmlData [ i ] ;
288+ i ++ ;
289+ }
290+
291+ // Validate notation name
292+ notation = notation . trim ( ) ;
293+ if ( ! validateEntityName ( notation ) ) {
294+ throw new Error ( `Invalid notation name: "${ notation } "` ) ;
295+ }
296+
297+ allowedNotations . push ( notation ) ;
298+
299+ // Skip '|' separator or exit loop
300+ if ( xmlData [ i ] === "|" ) {
301+ i ++ ; // Move past '|'
302+ i = skipWhitespace ( xmlData , i ) ; // Skip optional whitespace after '|'
303+ }
304+ }
305+
306+ if ( xmlData [ i ] !== ")" ) {
307+ throw new Error ( "Unterminated list of notations" ) ;
308+ }
309+ i ++ ; // Move past ')'
310+
311+ // Store the allowed notations as part of the attribute type
312+ attributeType += " (" + allowedNotations . join ( "|" ) + ")" ;
313+ } else {
314+ // Handle simple types (e.g., CDATA, ID, IDREF, etc.)
315+ while ( i < xmlData . length && ! / \s / . test ( xmlData [ i ] ) ) {
316+ attributeType += xmlData [ i ] ;
317+ i ++ ;
318+ }
319+
320+ // Validate simple attribute type
321+ const validTypes = [ "CDATA" , "ID" , "IDREF" , "IDREFS" , "ENTITY" , "ENTITIES" , "NMTOKEN" , "NMTOKENS" ] ;
322+ if ( ! validTypes . includes ( attributeType . toUpperCase ( ) ) ) {
323+ throw new Error ( `Invalid attribute type: "${ attributeType } "` ) ;
324+ }
325+ }
326+
327+ // Skip whitespace after attribute type
328+ i = skipWhitespace ( xmlData , i ) ;
329+
330+ // Read default value
331+ let defaultValue = "" ;
332+ if ( xmlData . substring ( i , i + 8 ) . toUpperCase ( ) === "#REQUIRED" ) {
333+ defaultValue = "#REQUIRED" ;
334+ i += 8 ;
335+ } else if ( xmlData . substring ( i , i + 7 ) . toUpperCase ( ) === "#IMPLIED" ) {
336+ defaultValue = "#IMPLIED" ;
337+ i += 7 ;
338+ } else {
339+ [ i , defaultValue ] = readIdentifierVal ( xmlData , i , "ATTLIST" ) ;
340+ }
341+
342+ return {
343+ elementName,
344+ attributeName,
345+ attributeType,
346+ defaultValue,
347+ index : i
348+ }
349+ }
350+
184351function isComment ( xmlData , i ) {
185352 if ( xmlData [ i + 1 ] === '!' &&
186353 xmlData [ i + 2 ] === '-' &&
0 commit comments