* Parse a DTD markup declaration (<!ENTITY, <!ELEMENT, <!ATTLIST, <!NOTATION, or comment).
()
| 287 | * Parse a DTD markup declaration (<!ENTITY, <!ELEMENT, <!ATTLIST, <!NOTATION, or comment). |
| 288 | */ |
| 289 | function parseDTDMarkupDeclaration(): void { |
| 290 | if (pos >= len) { |
| 291 | error("Unexpected end of input in DTD declaration"); |
| 292 | } |
| 293 | |
| 294 | // Check for comment |
| 295 | if (input.charCodeAt(pos) === CC_DASH) { |
| 296 | pos++; |
| 297 | if (pos >= len || input.charCodeAt(pos) !== CC_DASH) { |
| 298 | error("Expected '--' to start comment in DTD"); |
| 299 | } |
| 300 | pos++; |
| 301 | // Skip comment content |
| 302 | while (pos < len) { |
| 303 | if ( |
| 304 | input.charCodeAt(pos) === CC_DASH && |
| 305 | pos + 1 < len && |
| 306 | input.charCodeAt(pos + 1) === CC_DASH |
| 307 | ) { |
| 308 | pos += 2; |
| 309 | if (pos >= len || input.charCodeAt(pos) !== CC_GT) { |
| 310 | error("Cannot use '--' within XML comments (XML 1.0 §2.5)"); |
| 311 | } |
| 312 | pos++; |
| 313 | return; |
| 314 | } |
| 315 | pos++; |
| 316 | } |
| 317 | error("Unterminated comment in DTD"); |
| 318 | } |
| 319 | |
| 320 | // Read declaration keyword (ENTITY, ELEMENT, ATTLIST, NOTATION) |
| 321 | const kwStart = pos; |
| 322 | while ( |
| 323 | pos < len && |
| 324 | ((input.charCodeAt(pos) >= 65 && input.charCodeAt(pos) <= 90) || // A-Z |
| 325 | (input.charCodeAt(pos) >= 97 && input.charCodeAt(pos) <= 122)) // a-z |
| 326 | ) { |
| 327 | pos++; |
| 328 | } |
| 329 | const keyword = input.slice(kwStart, pos); |
| 330 | |
| 331 | if ( |
| 332 | keyword !== "ENTITY" && keyword !== "ELEMENT" && |
| 333 | keyword !== "ATTLIST" && keyword !== "NOTATION" |
| 334 | ) { |
| 335 | error(`Unknown DTD declaration type '<!${keyword}'`); |
| 336 | } |
| 337 | |
| 338 | // Must have whitespace after keyword |
| 339 | if (pos >= len || !isWhitespace(input.charCodeAt(pos))) { |
| 340 | error(`Missing whitespace after '<!${keyword}'`); |
| 341 | } |
| 342 | |
| 343 | // For ENTITY declarations, extract the entity name and value |
| 344 | if (keyword === "ENTITY") { |
| 345 | parseEntityDeclaration(); |
| 346 | } else { |
no test coverage detected