UNPKG

typesxml

Version:

Open source XML library written in TypeScript

229 lines 7.48 kB
/******************************************************************************* * Copyright (c) 2023-2026 Maxprograms. * * This program and the accompanying materials * are made available under the terms of the Eclipse License 1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/epl-v10.html * * Contributors: * Maxprograms - initial API and implementation *******************************************************************************/ import { CData } from "./CData.js"; import { ProcessingInstruction } from "./ProcessingInstruction.js"; import { TextNode } from "./TextNode.js"; import { XMLComment } from "./XMLComment.js"; import { XMLDeclaration } from "./XMLDeclaration.js"; import { XMLDocument } from "./XMLDocument.js"; import { XMLDocumentType } from "./XMLDocumentType.js"; import { XMLElement } from "./XMLElement.js"; import { XMLUtils } from "./XMLUtils.js"; import { DTDParser } from "./dtd/DTDParser.js"; import { DTDGrammar } from "./dtd/DTDGrammar.js"; export class DOMBuilder { inCdData = false; currentCData = new CData(''); document; stack = []; catalog; dtdParser; grammar; initialize() { this.document = new XMLDocument(); this.stack = new Array(); this.inCdData = false; } setGrammar(grammar) { this.grammar = grammar; if (grammar instanceof DTDGrammar) { if (!this.dtdParser) { this.dtdParser = new DTDParser(grammar); } else { this.dtdParser.setGrammar(grammar); } } } setCatalog(catalog) { this.catalog = catalog; } getDocument() { return this.document; } startDocument() { // do nothing } endDocument() { // do nothing } xmlDeclaration(version, encoding, standalone) { let xmlDclaration = new XMLDeclaration(version, encoding, standalone); this.document?.setXmlDeclaration(xmlDclaration); } startElement(name, atts) { let element = new XMLElement(name); atts.forEach((att) => { element.setAttribute(att); }); if (this.stack.length > 0) { this.stack[this.stack.length - 1].addElement(element); } else { this.document?.setRoot(element); } this.stack.push(element); } endElement(name) { this.stack.pop(); } getCurrentText() { if (this.stack.length > 0) { return this.stack[this.stack.length - 1].pureText(); } return ''; } internalSubset(declaration) { let docType = this.document?.getDocumentType(); if (docType) { docType.setInternalSubset(declaration); } } characters(ch) { if (this.inCdData) { this.currentCData.setValue(this.currentCData.getValue() + ch); return; } let textNode = new TextNode(ch); if (this.stack.length > 0) { this.stack[this.stack.length - 1].addTextNode(textNode); } else { this.document?.addTextNode(textNode); } } ignorableWhitespace(ch) { let textNode = new TextNode(ch); if (this.stack.length > 0) { this.stack[this.stack.length - 1].addTextNode(textNode); } else { this.document?.addTextNode(textNode); } } comment(ch) { let comment = new XMLComment(ch); if (this.stack.length > 0) { this.stack[this.stack.length - 1].addComment(comment); } else { this.document?.addComment(comment); } } processingInstruction(target, data) { let pi = new ProcessingInstruction(target, data); if (this.stack.length > 0) { this.stack[this.stack.length - 1].addProcessingInstruction(pi); } else { this.document?.addProcessingInstruction(pi); } } parseXmlModel(text) { let map = new Map(); let pairs = []; let separator = ''; while (text.indexOf('=') != -1) { let i = 0; for (; i < text.length; i++) { let char = text[i]; if (XMLUtils.isXmlSpace(char) || '=' === char) { break; } } for (; i < text.length; i++) { let char = text[i]; if (separator === '' && ('\'' === char || '"' === char)) { separator = char; continue; } if (char === separator) { break; } } // end of value let pair = text.substring(0, i + 1).trim(); pairs.push(pair); text = text.substring(pair.length).trim(); separator = ''; } pairs.forEach((pair) => { let index = pair.indexOf('='); if (index === -1) { throw new Error('Malformed attributes list'); } let name = pair.substring(0, index).trim(); let value = pair.substring(index + 2, pair.length - 1); map.set(name, value); }); return map; } startCDATA() { this.currentCData = new CData(''); this.inCdData = true; } endCDATA() { if (this.stack.length > 0) { this.stack[this.stack.length - 1].addCData(this.currentCData); } else { throw new Error("CData section outside of root element"); } this.inCdData = false; } startDTD(name, publicId, systemId) { let docType = new XMLDocumentType(name, publicId, systemId); this.document?.setDocumentType(docType); if (this.catalog) { const url = this.catalog.resolveEntity(publicId, systemId); if (url) { if (!this.dtdParser) { this.dtdParser = new DTDParser(); } const dtdGrammar = this.dtdParser.parseDTD(url); this.setGrammar(dtdGrammar); } } } endDTD() { // do nothing } getGrammar() { return this.grammar; } skippedEntity(name) { const replacement = this.grammar?.resolveEntity(name); if (replacement && replacement.length > 0) { this.characters(replacement); return; } if (this.grammar instanceof DTDGrammar) { const entityDecl = this.grammar.getEntity(name); if (entityDecl && entityDecl.isExternal() && this.dtdParser) { try { const externalText = this.dtdParser.loadExternalEntity(entityDecl.getPublicId(), entityDecl.getSystemId(), true); if (externalText.length > 0) { entityDecl.setValue(externalText); this.characters(externalText); return; } } catch (error) { throw new Error(`Could not resolve external entity "${name}": ${error.message}`); } } } // Preserve the reference if no replacement text is available this.characters('&' + name + ';'); } } //# sourceMappingURL=DOMBuilder.js.map