@@ -29,8 +29,11 @@ export default function readDocType(xmlData, i){
2929 }
3030 else if ( hasBody && isElement ( xmlData , i ) ) i += 8 ; //Not supported
3131 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 ;
3437 else throw new Error ( "Invalid DOCTYPE" ) ;
3538
3639 angleBracketsCount ++ ;
@@ -124,6 +127,80 @@ function readEntityExp(xmlData, i) {
124127 return [ entityName , entityValue , i ] ;
125128}
126129
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+ }
127204
128205function isComment ( xmlData , i ) {
129206 if ( xmlData [ i + 1 ] === '!' &&
0 commit comments