( attrName: string, attrValue: string, xml11: boolean, )
| 454 | * @returns Error message if invalid, null if valid. |
| 455 | */ |
| 456 | export function validateNamespaceBinding( |
| 457 | attrName: string, |
| 458 | attrValue: string, |
| 459 | xml11: boolean, |
| 460 | ): string | null { |
| 461 | const colonIndex = attrName.indexOf(":"); |
| 462 | const isDefaultNs = attrName === "xmlns"; |
| 463 | const prefix = isDefaultNs ? "" : attrName.slice(colonIndex + 1); |
| 464 | const uri = attrValue; |
| 465 | |
| 466 | // xmlns: with empty local part is caught by QName validation |
| 467 | // But check for empty prefix after xmlns: |
| 468 | if (colonIndex !== -1 && prefix === "") { |
| 469 | return "Cannot have empty namespace prefix after 'xmlns:'"; |
| 470 | } |
| 471 | |
| 472 | // Prefix unbinding: xmlns:foo="" is forbidden in NS 1.0, allowed in NS 1.1 |
| 473 | if (!isDefaultNs && uri === "" && !xml11) { |
| 474 | return "Cannot unbind namespace prefix (empty URI) in Namespaces 1.0"; |
| 475 | } |
| 476 | |
| 477 | // Cannot declare xmlns prefix at all |
| 478 | if (prefix === "xmlns") { |
| 479 | return "Cannot declare the 'xmlns' prefix"; |
| 480 | } |
| 481 | |
| 482 | // xml prefix must use correct URI |
| 483 | if (prefix === "xml" && uri !== XML_NAMESPACE) { |
| 484 | return `Cannot bind 'xml' prefix to '${uri}': must use '${XML_NAMESPACE}'`; |
| 485 | } |
| 486 | |
| 487 | // Only xml prefix can use xml namespace |
| 488 | if (uri === XML_NAMESPACE && prefix !== "xml" && prefix !== "") { |
| 489 | return `Cannot bind prefix '${prefix}' to '${XML_NAMESPACE}': only the 'xml' prefix may use this namespace`; |
| 490 | } |
| 491 | |
| 492 | // Nothing can bind to xmlns namespace (includes default namespace case) |
| 493 | if (uri === XMLNS_NAMESPACE) { |
| 494 | return `Cannot bind any prefix to '${XMLNS_NAMESPACE}'`; |
| 495 | } |
| 496 | |
| 497 | // Default namespace cannot be xml namespace |
| 498 | if (isDefaultNs && uri === XML_NAMESPACE) { |
| 499 | return `Cannot use '${XML_NAMESPACE}' as the default namespace`; |
| 500 | } |
| 501 | |
| 502 | return null; // Valid binding |
| 503 | } |
| 504 | |
| 505 | /** |
| 506 | * Validates a PubidLiteral per XML 1.0 §2.3. |
no test coverage detected