UNPKG

libxslt-wasm

Version:

JavaScript bindings for libxslt compiled to WebAssembly

103 lines (102 loc) 4.37 kB
import { XmlDocument } from "./XmlDocument.js"; import { XmlOutputBuffer } from "./XmlOutputBuffer.js"; import { NULL_POINTER } from "../constants.js"; import { xsltApplyStylesheet, xsltLoadStylesheetPI, xsltFreeStylesheet, xsltParseStylesheetDoc, xsltSaveResultTo, } from "../internal/libxslt.js"; import { StringPtrArray } from "../utils/StringPtrArray.js"; // If you see errors when passing params, considering double quoting params so // they are considered literals rather than XPath expressions const parseXsltParams = (params) => { if (params === undefined) { return NULL_POINTER; } const entries = Object.entries(params); if (entries.length === 0) { return NULL_POINTER; } const paramArray = entries .map(([key, value]) => [key, String(value)]) .flat(1); const paramsArrayPtr = StringPtrArray.fromStringArray(paramArray, true).dataOffset; if (paramsArrayPtr === null) { throw new Error("Failed to allocate memory for XSLT parameters"); } return paramsArrayPtr; }; class XsltStylesheet extends XmlDocument { /** * Assuming the XML document is a valid XSLT stylesheet, creates a new * instance of XsltStylesheet */ static async fromXmlDocument(xmlDocument) { if (xmlDocument.dataOffset === null) { throw new Error("XML document has already been disposed"); } const xsltStylesheet = await xsltParseStylesheetDoc(xmlDocument.dataOffset); return new XsltStylesheet(xsltStylesheet); } /** * Given an XML document with an embedded XSLT stylesheet (e.g. a processing * instruction like <?xml-stylesheet?>), return the corresponding * XsltStylesheet instance */ static async fromEmbeddedXmlDocument(xmlDocument) { if (xmlDocument.dataOffset === null) { throw new Error("XML document has already been disposed"); } const xsltStylesheetPtr = await xsltLoadStylesheetPI(xmlDocument.dataOffset); return xsltStylesheetPtr === NULL_POINTER ? null : (new XsltStylesheet(xsltStylesheetPtr)); } static async fromFileOrUrl(fileOrUrl) { return this.fromXmlDocument(await super.fromFileOrUrl(fileOrUrl)); } static async fromString(string) { return this.fromXmlDocument(await super.fromString(string)); } // Since `xsltApplyStylesheet()` uses `xmlXPathCompOpEval()` internally for // params, this must be async. Consider using `applyToOutputBuffer()` or // `applyToString()` for synchronous operations async apply(xmlDocument, params) { if (this.dataOffset === null) { throw new Error("XSLT stylesheet has already been disposed"); } else if (xmlDocument.dataOffset === null) { throw new Error("XML document has already been disposed"); } const result = await xsltApplyStylesheet(this.dataOffset, xmlDocument.dataOffset, parseXsltParams(params)); if (result === NULL_POINTER) { throw new Error("Failed to apply XSLT stylesheet to XML document"); } return new XmlDocument(result); } applyToOutputBuffer(xmlDocument) { if (this.dataOffset === null) { throw new Error("XSLT stylesheet has already been disposed"); } else if (xmlDocument.dataOffset === null) { throw new Error("XML document has already been disposed"); } const outputBuffer = XmlOutputBuffer.allocate(); if (outputBuffer.dataOffset === null) { throw new Error("Failed to allocate memory for XML output buffer"); } const bytesWritten = xsltSaveResultTo(outputBuffer.dataOffset, xmlDocument.dataOffset, this.dataOffset); if (bytesWritten === -1) { throw new Error("Failed to save result to XML output buffer"); } return outputBuffer; } applyToString(xmlDocument) { const outputBuffer = this.applyToOutputBuffer(xmlDocument); const result = outputBuffer.toString(); outputBuffer.delete(); return result; } delete() { if (this.dataOffset !== null) { xsltFreeStylesheet(this.dataOffset); } this.dataOffset = null; // Do NOT call `super.delete()` since `xmlFreeDoc()` will be called } } export { XsltStylesheet };