libxslt-wasm
Version:
JavaScript bindings for libxslt compiled to WebAssembly
123 lines (122 loc) • 5.18 kB
JavaScript
import { XmlOutputBuffer } from "./XmlOutputBuffer.js";
import { DataSegment } from "../common/DataSegment.js";
import { NULL_POINTER } from "../constants.js";
import { stringToNewUTF8, HEAPU8 } from "../internal/emscripten.js";
import { xmlReadFile, xmlReadDoc, xmlReadMemory, xmlNodeDumpOutput, xmlFreeDoc, htmlDocContentDumpFormatOutput, } from "../internal/libxml2.js";
import { free, malloc } from "../internal/main.js";
import { parseXmlOptions } from "../utils/parseXmlOptions.js";
/**
* A wrapper class for `xmlDocPtr` in libxml2
*/
class XmlDocument extends DataSegment {
static async fromUrl(url, { encoding, options } = {}) {
const encodingPtr = encoding ? stringToNewUTF8(encoding) : null;
const urlPtr = stringToNewUTF8(url);
const xmlDocumentPtr = await xmlReadFile(urlPtr, encodingPtr ?? NULL_POINTER, parseXmlOptions(options ?? {}));
if (encodingPtr !== null) {
free(encodingPtr);
}
free(urlPtr);
if (xmlDocumentPtr === NULL_POINTER) {
throw new Error("Invalid XMLDocument");
}
return new XmlDocument(xmlDocumentPtr);
}
static async fromString(xmlString, { encoding, url, options } = {}) {
const xmlStringPtr = stringToNewUTF8(xmlString);
const urlPtr = url ? stringToNewUTF8(url) : null;
const encodingPtr = encoding ? stringToNewUTF8(encoding) : null;
const xmlDocumentPtr = await xmlReadDoc(xmlStringPtr ?? NULL_POINTER, urlPtr ?? NULL_POINTER, encodingPtr ?? NULL_POINTER, parseXmlOptions(options ?? {}));
free(xmlStringPtr);
if (encodingPtr !== null) {
free(encodingPtr);
}
if (urlPtr !== null) {
free(urlPtr);
}
if (xmlDocumentPtr === NULL_POINTER) {
throw new Error("Invalid XMLDocument");
}
return new XmlDocument(xmlDocumentPtr);
}
static async fromBuffer(buffer, options) {
return this.from(new Uint8Array(buffer), options);
}
static async from(data, { url, encoding, options } = {}) {
const bufferPtr = malloc(data.byteLength);
HEAPU8.set(data, bufferPtr);
const urlPtr = url ? stringToNewUTF8(url) : null;
const encodingPtr = encoding ? stringToNewUTF8(encoding) : null;
const xmlDocumentPtr = await xmlReadMemory(bufferPtr, data.byteLength, urlPtr ?? NULL_POINTER, encodingPtr ?? NULL_POINTER, parseXmlOptions(options ?? {}));
if (encodingPtr !== null) {
free(encodingPtr);
}
if (urlPtr !== null) {
free(urlPtr);
}
free(bufferPtr);
if (xmlDocumentPtr === NULL_POINTER) {
throw new Error("Invalid XMLDocument");
}
return new XmlDocument(xmlDocumentPtr);
}
delete() {
if (this.byteOffset !== NULL_POINTER) {
xmlFreeDoc(this.byteOffset);
}
}
toXmlOutputBuffer(options) {
const xmlOutputBuffer = XmlOutputBuffer.allocate();
const encodingPtr = options?.encoding ? stringToNewUTF8(options.encoding) : null;
/**
* Since `xmlDocPtr` is a super pointer to `xmlNodePtr`, it can be passed to
* `cur`. While this usage may be suspect, this technique is used for for
* `htmlDocContentDumpOutput`.
*
* @see {@link https://gitlab.gnome.org/GNOME/libxml2/-/blob/master/HTMLtree.c#L938-942}
*/
xmlNodeDumpOutput(xmlOutputBuffer.byteOffset ?? NULL_POINTER,
/* doc */ this.byteOffset ?? NULL_POINTER,
/* cur */ this.byteOffset ?? NULL_POINTER,
/* level */ 0, options?.format ? 1 : 0,
/* encoding */ encodingPtr ?? NULL_POINTER);
if (encodingPtr !== NULL_POINTER) {
free(encodingPtr);
}
return xmlOutputBuffer;
}
/**
* Formats the XML document as a string by dumping the XML tree to an
* {@link XmlOutputBuffer} and returning its string representation.
*/
toString(options) {
const xmlOutputBuffer = this.toXmlOutputBuffer(options);
const xmlString = xmlOutputBuffer.toString();
xmlOutputBuffer.delete();
return xmlString;
}
/**
* Assuming the document is an HTML tree, dumps the document to an
* {@link XmlOutputBuffer} and returns the output buffer
*/
toHtmlOutputBuffer(options) {
const htmlOutputBuffer = XmlOutputBuffer.allocate();
const encodingPtr = options?.encoding ? stringToNewUTF8(options.encoding) : null;
htmlDocContentDumpFormatOutput(htmlOutputBuffer.byteOffset, this.byteOffset, encodingPtr ?? NULL_POINTER, options?.format ? 1 : 0);
if (encodingPtr !== null) {
free(encodingPtr);
}
return htmlOutputBuffer;
}
/**
* Assuming the document is an HTML tree, serializes the document via
* {@link toHtmlOutputBuffer} and returns the string
*/
toHtmlString(options) {
const htmlOutputBuffer = this.toHtmlOutputBuffer(options);
const xmlString = htmlOutputBuffer.toString();
htmlOutputBuffer.delete();
return xmlString;
}
}
export { XmlDocument };