xmlbuilder2
Advanced tools
Comparing version 0.0.9 to 0.0.10
@@ -1,2 +0,2 @@ | ||
import { Node, Document, DocumentType, DocumentFragment, Attr, Text, CDATASection, Comment, ProcessingInstruction, Element } from "@oozcitak/dom/lib/dom/interfaces"; | ||
import { Node, Document } from "@oozcitak/dom/lib/dom/interfaces"; | ||
/** | ||
@@ -13,5 +13,5 @@ * Represents a document with XML builder settings applied. | ||
/** | ||
* A version number string, e.g. `"1.0"`. Defaults to `"1.0"`. | ||
* A version number string, always `"1.0"`. | ||
*/ | ||
version?: "1.0" | "1.1"; | ||
version?: "1.0"; | ||
/** | ||
@@ -52,3 +52,3 @@ * Encoding declaration, e.g. `"UTF-8"`. No default. | ||
*/ | ||
version: "1.0" | "1.1"; | ||
version: "1.0"; | ||
/** | ||
@@ -396,3 +396,3 @@ * Encoding declaration, e.g. `"UTF-8"` | ||
*/ | ||
readonly as: CastAsNode; | ||
readonly node: Node; | ||
/** | ||
@@ -553,3 +553,3 @@ * Sets builder options. | ||
dec(options: { | ||
version: "1.0" | "1.1"; | ||
version?: "1.0"; | ||
encoding?: string; | ||
@@ -613,83 +613,106 @@ standalone?: boolean; | ||
/** | ||
* Traverses through the child nodes of an element node. | ||
* Traverses through the child nodes of a node. `callback` is called with two | ||
* arguments: `(node, index)`. | ||
* | ||
* @param callback - a callback function to apply to each node | ||
* @param callback - a callback function to apply to each child node | ||
* @param self - whether to visit the current node along with child nodes | ||
* @param recursive - whether to visit all descendant nodes in tree-order or | ||
* only the immediate child nodes | ||
* @param thisArg - value to use as this when executing callback | ||
*/ | ||
forEachChild(callback: (node: XMLBuilder) => void, thisArg?: any): XMLBuilder; | ||
each(callback: ((node: XMLBuilder, index: number) => void), self?: boolean, recursive?: boolean, thisArg?: any): XMLBuilder; | ||
/** | ||
* Traverses through the attributes of an element node. | ||
* Produces an array of values by transforming each child node with the given | ||
* callback function. `callback` is called with two arguments: `(node, index)`. | ||
* | ||
* @param callback - a callback function to apply to each attribute | ||
* @param callback - a callback function to apply to each child node | ||
* @param self - whether to visit the current node along with child nodes | ||
* @param recursive - whether to visit all descendant nodes in tree-order or | ||
* only the immediate child nodes | ||
* @param thisArg - value to use as this when executing callback | ||
*/ | ||
forEachAttribute(callback: (node: XMLBuilder) => void, thisArg?: any): XMLBuilder; | ||
map<T>(callback: ((node: XMLBuilder, index: number) => T), self?: boolean, recursive?: boolean, thisArg?: any): T[]; | ||
/** | ||
* Converts the node into its string representation. | ||
* Reduces child nodes into a single value by applying the given callback | ||
* function. `callback` is called with three arguments: `(value, node, index)`. | ||
* | ||
* @param options - serialization options | ||
* @param callback - a callback function to apply to each child node | ||
* @param initialValue - initial value of the iteration | ||
* @param self - whether to visit the current node along with child nodes | ||
* @param recursive - whether to visit all descendant nodes in tree-order or | ||
* only the immediate child nodes | ||
* @param thisArg - value to use as this when executing callback | ||
*/ | ||
toString(writerOptions?: JSONWriterOptions | StringWriterOptions): string; | ||
reduce<T>(callback: ((value: T, node: XMLBuilder, index: number) => T), initialValue: T, self?: boolean, recursive?: boolean, thisArg?: any): T; | ||
/** | ||
* Converts the node into its object representation. | ||
* Returns the first child node satisfying the given predicate. `predicate` is | ||
* called with two arguments: `(node, index)`. | ||
* | ||
* @param options - serialization options | ||
* @param predicate - a callback function to apply to each child node | ||
* @param self - whether to visit the current node along with child nodes | ||
* @param recursive - whether to visit all descendant nodes in tree-order or | ||
* only the immediate child nodes | ||
* @param thisArg - value to use as this when executing predicate | ||
*/ | ||
toObject(writerOptions?: MapWriterOptions | ObjectWriterOptions): XMLSerializedValue; | ||
find(predicate: ((node: XMLBuilder, index: number) => boolean), self?: boolean, recursive?: boolean, thisArg?: any): XMLBuilder | undefined; | ||
/** | ||
* Converts the entire XML document into its string or object representation. | ||
* Produces an array of child nodes which pass the given predicate test. | ||
* `predicate` is called with two arguments: `(node, index)`. | ||
* | ||
* @param options - serialization options | ||
* @param predicate - a callback function to apply to each child node | ||
* @param self - whether to visit the current node along with child nodes | ||
* @param recursive - whether to visit all descendant nodes in tree-order or | ||
* only the immediate child nodes | ||
* @param thisArg - value to use as this when executing predicate | ||
*/ | ||
end(writerOptions?: WriterOptions): XMLSerializedValue; | ||
} | ||
/** | ||
* Returns underlying DOM nodes. | ||
*/ | ||
export interface CastAsNode { | ||
filter(predicate: ((node: XMLBuilder, index: number) => boolean), self?: boolean, recursive?: boolean, thisArg?: any): XMLBuilder[]; | ||
/** | ||
* Casts to `any` to call methods without a TypeScript definition. | ||
* Returns `true` if all child nodes pass the given predicate test. | ||
* `predicate` is called with two arguments: `(node, index)`. | ||
* | ||
* @param predicate - a callback function to apply to each child node | ||
* @param self - whether to visit the current node along with child nodes | ||
* @param recursive - whether to visit all descendant nodes in tree-order or | ||
* only the immediate child nodes | ||
* @param thisArg - value to use as this when executing predicate | ||
*/ | ||
readonly any: any; | ||
every(predicate: ((node: XMLBuilder, index: number) => boolean), self?: boolean, recursive?: boolean, thisArg?: any): boolean; | ||
/** | ||
* Returns the underlying DOM node. | ||
* Returns `true` if any of the child nodes pass the given predicate test. | ||
* `predicate` is called with two arguments: `(node, index)`. | ||
* | ||
* @param predicate - a callback function to apply to each child node | ||
* @param self - whether to visit the current node along with child nodes | ||
* @param recursive - whether to visit all descendant nodes in tree-order or | ||
* only the immediate child nodes | ||
* @param thisArg - value to use as this when executing predicate | ||
*/ | ||
readonly node: Node; | ||
some(predicate: ((node: XMLBuilder, index: number) => boolean), self?: boolean, recursive?: boolean, thisArg?: any): boolean; | ||
/** | ||
* Returns the underlying DOM document node. | ||
* Produces an array of child nodes. | ||
* | ||
* @param self - whether to visit the current node along with child nodes | ||
* @param recursive - whether to visit all descendant nodes in tree-order or | ||
* only the immediate child nodes | ||
*/ | ||
readonly document: Document; | ||
toArray(self?: boolean, recursive?: boolean): XMLBuilder[]; | ||
/** | ||
* Returns the underlying DOM document type node. | ||
* Converts the node into its string representation. | ||
* | ||
* @param options - serialization options | ||
*/ | ||
readonly documentType: DocumentType; | ||
toString(writerOptions?: JSONWriterOptions | StringWriterOptions): string; | ||
/** | ||
* Returns the underlying DOM document fragment node. | ||
* Converts the node into its object representation. | ||
* | ||
* @param options - serialization options | ||
*/ | ||
readonly documentFragment: DocumentFragment; | ||
toObject(writerOptions?: MapWriterOptions | ObjectWriterOptions): XMLSerializedValue; | ||
/** | ||
* Returns the underlying DOM attr node. | ||
* Converts the entire XML document into its string or object representation. | ||
* | ||
* @param options - serialization options | ||
*/ | ||
readonly attr: Attr; | ||
/** | ||
* Returns the underlying DOM text node. | ||
*/ | ||
readonly text: Text; | ||
/** | ||
* Returns the underlying DOM cdata section node. | ||
*/ | ||
readonly cdataSection: CDATASection; | ||
/** | ||
* Returns the underlying DOM comment node. | ||
*/ | ||
readonly comment: Comment; | ||
/** | ||
* Returns the underlying DOM processing instruction node. | ||
*/ | ||
readonly processingInstruction: ProcessingInstruction; | ||
/** | ||
* Returns the underlying DOM element node. | ||
*/ | ||
readonly element: Element; | ||
end(writerOptions?: WriterOptions): XMLSerializedValue; | ||
} | ||
export {}; |
@@ -1,2 +0,2 @@ | ||
import { XMLBuilderOptions, XMLBuilder, AttributesObject, ExpandObject, WriterOptions, XMLSerializedValue, DTDOptions, CastAsNode, PIObject } from "./interfaces"; | ||
import { XMLBuilderOptions, XMLBuilder, AttributesObject, ExpandObject, WriterOptions, XMLSerializedValue, DTDOptions, PIObject } from "./interfaces"; | ||
import { Document, Node } from "@oozcitak/dom/lib/dom/interfaces"; | ||
@@ -9,3 +9,2 @@ /** | ||
private _domNode; | ||
private _castAsNode?; | ||
/** | ||
@@ -18,3 +17,3 @@ * Initializes a new instance of `XMLBuilderNodeImpl`. | ||
/** @inheritdoc */ | ||
get as(): CastAsNode; | ||
get node(): Node; | ||
/** @inheritdoc */ | ||
@@ -40,3 +39,3 @@ set(options: Partial<XMLBuilderOptions>): XMLBuilder; | ||
dec(options: { | ||
version: "1.0" | "1.1"; | ||
version?: "1.0"; | ||
encoding?: string; | ||
@@ -64,6 +63,18 @@ standalone?: boolean; | ||
/** @inheritdoc */ | ||
forEachChild(callback: (node: XMLBuilder) => void, thisArg?: any): XMLBuilder; | ||
each(callback: ((node: XMLBuilder, index: number) => void), self?: boolean, recursive?: boolean, thisArg?: any): XMLBuilder; | ||
/** @inheritdoc */ | ||
forEachAttribute(callback: (node: XMLBuilder) => void, thisArg?: any): XMLBuilder; | ||
map<T>(callback: ((node: XMLBuilder, index: number) => T), self?: boolean, recursive?: boolean, thisArg?: any): T[]; | ||
/** @inheritdoc */ | ||
reduce<T>(callback: ((value: T, node: XMLBuilder, index: number) => T), initialValue: T, self?: boolean, recursive?: boolean, thisArg?: any): T; | ||
/** @inheritdoc */ | ||
find(predicate: ((node: XMLBuilder, index: number) => boolean), self?: boolean, recursive?: boolean, thisArg?: any): XMLBuilder | undefined; | ||
/** @inheritdoc */ | ||
filter(predicate: ((node: XMLBuilder, index: number) => boolean), self?: boolean, recursive?: boolean, thisArg?: any): XMLBuilder[]; | ||
/** @inheritdoc */ | ||
every(predicate: ((node: XMLBuilder, index: number) => boolean), self?: boolean, recursive?: boolean, thisArg?: any): boolean; | ||
/** @inheritdoc */ | ||
some(predicate: ((node: XMLBuilder, index: number) => boolean), self?: boolean, recursive?: boolean, thisArg?: any): boolean; | ||
/** @inheritdoc */ | ||
toArray(self?: boolean, recursive?: boolean): XMLBuilder[]; | ||
/** @inheritdoc */ | ||
toString(writerOptions?: WriterOptions): string; | ||
@@ -75,2 +86,22 @@ /** @inheritdoc */ | ||
/** | ||
* Gets the next descendant of the given node of the tree rooted at `root` | ||
* in depth-first pre-order. | ||
* | ||
* @param root - root node of the tree | ||
* @param self - whether to visit the current node along with child nodes | ||
* @param recursive - whether to visit all descendant nodes in tree-order or | ||
* only the immediate child nodes | ||
*/ | ||
private _getFirstDescendantNode; | ||
/** | ||
* Gets the next descendant of the given node of the tree rooted at `root` | ||
* in depth-first pre-order. | ||
* | ||
* @param root - root node of the tree | ||
* @param node - current node | ||
* @param recursive - whether to visit all descendant nodes in tree-order or | ||
* only the immediate child nodes | ||
*/ | ||
private _getNextDescendantNode; | ||
/** | ||
* Converts the node into its string or object representation. | ||
@@ -77,0 +108,0 @@ * |
@@ -7,3 +7,2 @@ "use strict"; | ||
const writers_1 = require("../writers"); | ||
const CastAsNode_1 = require("./CastAsNode"); | ||
const dom_1 = require("./dom"); | ||
@@ -24,8 +23,3 @@ /** | ||
/** @inheritdoc */ | ||
get as() { | ||
if (this._castAsNode === undefined) { | ||
this._castAsNode = new CastAsNode_1.CastAsNodeImpl(this._domNode); | ||
} | ||
return this._castAsNode; | ||
} | ||
get node() { return this._domNode; } | ||
/** @inheritdoc */ | ||
@@ -52,2 +46,3 @@ set(options) { | ||
} | ||
dom_1.throwIfParserError(doc); | ||
for (const child of doc.documentElement.childNodes) { | ||
@@ -91,10 +86,8 @@ const newChild = doc.importNode(child, true); | ||
} | ||
else if (util_1.isArray(name)) { | ||
for (const item of util_1.forEachArray(name)) { | ||
lastChild = this.ele(item); | ||
} | ||
else if (util_1.isArray(name) || util_1.isSet(name)) { | ||
util_1.forEachArray(name, item => lastChild = this.ele(item), this); | ||
} | ||
else if (util_1.isMap(name) || util_1.isObject(name)) { | ||
// expand if object | ||
for (let [key, val] of util_1.forEachObject(name)) { | ||
util_1.forEachObject(name, (key, val) => { | ||
if (util_1.isFunction(val)) { | ||
@@ -115,3 +108,3 @@ // evaluate if function | ||
// text node | ||
if (util_1.isObject(val) || util_1.isMap(val)) { | ||
if (util_1.isMap(val) || util_1.isObject(val)) { | ||
// if the key is #text expand child nodes under this node to support mixed content | ||
@@ -126,6 +119,4 @@ lastChild = this.ele(val); | ||
// cdata node | ||
if (util_1.isArray(val)) { | ||
for (const item of util_1.forEachArray(val)) { | ||
lastChild = this.dat(item); | ||
} | ||
if (util_1.isArray(val) || util_1.isSet(val)) { | ||
util_1.forEachArray(val, item => lastChild = this.dat(item), this); | ||
} | ||
@@ -138,6 +129,4 @@ else { | ||
// comment node | ||
if (util_1.isArray(val)) { | ||
for (const item of util_1.forEachArray(val)) { | ||
lastChild = this.com(item); | ||
} | ||
if (util_1.isArray(val) || util_1.isSet(val)) { | ||
util_1.forEachArray(val, item => lastChild = this.com(item), this); | ||
} | ||
@@ -160,7 +149,7 @@ else { | ||
} | ||
else if (util_1.isArray(val) && util_1.isEmpty(val)) { | ||
else if ((util_1.isArray(val) || util_1.isSet(val)) && util_1.isEmpty(val)) { | ||
// skip empty arrays | ||
lastChild = this._dummy(); | ||
} | ||
else if (util_1.isObject(val) && util_1.isEmpty(val)) { | ||
else if ((util_1.isMap(val) || util_1.isObject(val)) && util_1.isEmpty(val)) { | ||
// empty objects produce one node | ||
@@ -173,14 +162,14 @@ lastChild = this.ele(key); | ||
} | ||
else if (util_1.isArray(val)) { | ||
else if (util_1.isArray(val) || util_1.isSet(val)) { | ||
// expand list by creating child nodes | ||
for (const item of util_1.forEachArray(val)) { | ||
util_1.forEachArray(val, item => { | ||
const childNode = {}; | ||
childNode[key] = item; | ||
lastChild = this.ele(childNode); | ||
} | ||
}, this); | ||
} | ||
else if (util_1.isObject(val) || util_1.isMap(val)) { | ||
else if (util_1.isMap(val) || util_1.isObject(val)) { | ||
// check for a namespace declaration attribute | ||
const qName = dom_1.extractQName(key); | ||
for (const [attName, attValue] of util_1.forEachObject(val)) { | ||
util_1.forEachObject(val, (attName, attValue) => { | ||
if (attName[0] === this._options.convert.att) { | ||
@@ -193,3 +182,3 @@ const attQName = dom_1.extractQName(attName.slice(1)); | ||
} | ||
} | ||
}, this); | ||
// create a parent node | ||
@@ -209,3 +198,3 @@ lastChild = this._node(namespace, key); | ||
} | ||
} | ||
}, this); | ||
} | ||
@@ -224,3 +213,3 @@ else { | ||
const parent = this.up(); | ||
parent.as.node.removeChild(this.as.node); | ||
parent.node.removeChild(this.node); | ||
return parent; | ||
@@ -233,5 +222,3 @@ } | ||
// expand if object | ||
for (const [attName, attValue] of util_1.forEachObject(p1)) { | ||
this.att(attName, attValue); | ||
} | ||
util_1.forEachObject(p1, (attName, attValue) => this.att(attName, attValue), this); | ||
return this; | ||
@@ -273,3 +260,3 @@ } | ||
} | ||
const ele = this.as.element; | ||
const ele = this.node; | ||
// convert to string | ||
@@ -308,21 +295,17 @@ if (namespace !== undefined && namespace !== null) | ||
} | ||
if (util_1.isArray(p1)) { | ||
if (util_1.isArray(p1) || util_1.isSet(p1)) { | ||
// removeAtt(names: string[]) | ||
for (const attName of util_1.forEachArray(p1)) { | ||
this.removeAtt(attName); | ||
} | ||
util_1.forEachArray(p1, attName => this.removeAtt(attName), this); | ||
} | ||
else if (util_1.isArray(p2)) { | ||
else if (util_1.isArray(p2) || util_1.isSet(p2)) { | ||
// removeAtt(namespace: string, names: string[]) | ||
for (const attName of util_1.forEachArray(p2)) { | ||
this.removeAtt(p1 + "", attName); | ||
} | ||
util_1.forEachArray(p2, attName => this.removeAtt(p1 + "", attName), this); | ||
} | ||
else if (p1 !== undefined && p2 !== undefined) { | ||
// removeAtt(namespace: string, name: string) | ||
this.as.element.removeAttributeNS(p1 + "", p2 + ""); | ||
this.node.removeAttributeNS(p1 + "", p2 + ""); | ||
} | ||
else { | ||
// removeAtt(name: string) | ||
this.as.element.removeAttribute(p1 + ""); | ||
this.node.removeAttribute(p1 + ""); | ||
} | ||
@@ -334,3 +317,3 @@ return this; | ||
const child = this._doc.createTextNode(content + ""); | ||
this.as.node.appendChild(child); | ||
this.node.appendChild(child); | ||
return this; | ||
@@ -341,3 +324,3 @@ } | ||
const child = this._doc.createComment(content + ""); | ||
this.as.node.appendChild(child); | ||
this.node.appendChild(child); | ||
return this; | ||
@@ -348,3 +331,3 @@ } | ||
const child = this._doc.createCDATASection(content + ""); | ||
this.as.node.appendChild(child); | ||
this.node.appendChild(child); | ||
return this; | ||
@@ -354,4 +337,4 @@ } | ||
ins(target, content = '') { | ||
if (util_1.isArray(target)) { | ||
for (let item of util_1.forEachArray(target)) { | ||
if (util_1.isArray(target) || util_1.isSet(target)) { | ||
util_1.forEachArray(target, item => { | ||
item += ""; | ||
@@ -362,12 +345,10 @@ const insIndex = item.indexOf(' '); | ||
this.ins(insTarget, insValue); | ||
} | ||
}, this); | ||
} | ||
else if (util_1.isMap(target) || util_1.isObject(target)) { | ||
for (const [insTarget, insValue] of util_1.forEachObject(target)) { | ||
this.ins(insTarget, insValue); | ||
} | ||
util_1.forEachObject(target, (insTarget, insValue) => this.ins(insTarget, insValue), this); | ||
} | ||
else { | ||
const child = this._doc.createProcessingInstruction(target + "", content + ""); | ||
this.as.node.appendChild(child); | ||
this.node.appendChild(child); | ||
} | ||
@@ -378,3 +359,3 @@ return this; | ||
dec(options) { | ||
this._options.version = options.version; | ||
this._options.version = options.version || "1.0"; | ||
this._options.encoding = options.encoding; | ||
@@ -404,3 +385,3 @@ this._options.standalone = options.standalone; | ||
const hostDoc = this._doc; | ||
const importedNode = node.as.node; | ||
const importedNode = node.node; | ||
if (dom_1.isDocumentNode(importedNode)) { | ||
@@ -482,12 +463,79 @@ // import document node | ||
/** @inheritdoc */ | ||
forEachChild(callback, thisArg) { | ||
this._domNode.childNodes.forEach(node => callback.call(thisArg, (new XMLBuilderImpl(node)))); | ||
each(callback, self = false, recursive = false, thisArg) { | ||
let node = this._getFirstDescendantNode(this._domNode, self, recursive); | ||
let index = 0; | ||
while (node) { | ||
callback.call(thisArg, new XMLBuilderImpl(node), index++); | ||
node = this._getNextDescendantNode(this._domNode, node, recursive); | ||
} | ||
return this; | ||
} | ||
/** @inheritdoc */ | ||
forEachAttribute(callback, thisArg) { | ||
this.as.element.attributes._attributeList.forEach(node => callback.call(thisArg, (new XMLBuilderImpl(node)))); | ||
return this; | ||
map(callback, self = false, recursive = false, thisArg) { | ||
let result = []; | ||
this.each((node, index) => result.push(callback.call(thisArg, node, index)), self, recursive); | ||
return result; | ||
} | ||
/** @inheritdoc */ | ||
reduce(callback, initialValue, self = false, recursive = false, thisArg) { | ||
let value = initialValue; | ||
this.each((node, index) => value = callback.call(thisArg, value, node, index), self, recursive); | ||
return value; | ||
} | ||
/** @inheritdoc */ | ||
find(predicate, self = false, recursive = false, thisArg) { | ||
let node = this._getFirstDescendantNode(this._domNode, self, recursive); | ||
let index = 0; | ||
while (node) { | ||
const builder = new XMLBuilderImpl(node); | ||
if (predicate.call(thisArg, builder, index++)) { | ||
return builder; | ||
} | ||
node = this._getNextDescendantNode(this._domNode, node, recursive); | ||
} | ||
return undefined; | ||
} | ||
/** @inheritdoc */ | ||
filter(predicate, self = false, recursive = false, thisArg) { | ||
let result = []; | ||
this.each((node, index) => { | ||
if (predicate.call(thisArg, node, index)) { | ||
result.push(node); | ||
} | ||
}, self, recursive); | ||
return result; | ||
} | ||
/** @inheritdoc */ | ||
every(predicate, self = false, recursive = false, thisArg) { | ||
let node = this._getFirstDescendantNode(this._domNode, self, recursive); | ||
let index = 0; | ||
while (node) { | ||
const builder = new XMLBuilderImpl(node); | ||
if (!predicate.call(thisArg, builder, index++)) { | ||
return false; | ||
} | ||
node = this._getNextDescendantNode(this._domNode, node, recursive); | ||
} | ||
return true; | ||
} | ||
/** @inheritdoc */ | ||
some(predicate, self = false, recursive = false, thisArg) { | ||
let node = this._getFirstDescendantNode(this._domNode, self, recursive); | ||
let index = 0; | ||
while (node) { | ||
const builder = new XMLBuilderImpl(node); | ||
if (predicate.call(thisArg, builder, index++)) { | ||
return true; | ||
} | ||
node = this._getNextDescendantNode(this._domNode, node, recursive); | ||
} | ||
return false; | ||
} | ||
/** @inheritdoc */ | ||
toArray(self = false, recursive = false) { | ||
let result = []; | ||
this.each((node) => result.push(node), self, recursive); | ||
return result; | ||
} | ||
/** @inheritdoc */ | ||
toString(writerOptions) { | ||
@@ -517,2 +565,54 @@ writerOptions = writerOptions || {}; | ||
/** | ||
* Gets the next descendant of the given node of the tree rooted at `root` | ||
* in depth-first pre-order. | ||
* | ||
* @param root - root node of the tree | ||
* @param self - whether to visit the current node along with child nodes | ||
* @param recursive - whether to visit all descendant nodes in tree-order or | ||
* only the immediate child nodes | ||
*/ | ||
_getFirstDescendantNode(root, self, recursive) { | ||
if (self) | ||
return this._domNode; | ||
else if (recursive) | ||
return this._getNextDescendantNode(root, root, recursive); | ||
else | ||
return this._domNode.firstChild; | ||
} | ||
/** | ||
* Gets the next descendant of the given node of the tree rooted at `root` | ||
* in depth-first pre-order. | ||
* | ||
* @param root - root node of the tree | ||
* @param node - current node | ||
* @param recursive - whether to visit all descendant nodes in tree-order or | ||
* only the immediate child nodes | ||
*/ | ||
_getNextDescendantNode(root, node, recursive) { | ||
if (recursive) { | ||
// traverse child nodes | ||
if (node.firstChild) | ||
return node.firstChild; | ||
if (node === root) | ||
return null; | ||
// traverse siblings | ||
if (node.nextSibling) | ||
return node.nextSibling; | ||
// traverse parent's next sibling | ||
let parent = node.parentNode; | ||
while (parent && parent !== root) { | ||
if (parent.nextSibling) | ||
return parent.nextSibling; | ||
parent = parent.parentNode; | ||
} | ||
} | ||
else { | ||
if (root === node) | ||
return node.firstChild; | ||
else | ||
return node.nextSibling; | ||
} | ||
return null; | ||
} | ||
/** | ||
* Converts the node into its string or object representation. | ||
@@ -525,15 +625,15 @@ * | ||
const writer = new writers_1.StringWriterImpl(this._options); | ||
return writer.serialize(this.as.node, writerOptions); | ||
return writer.serialize(this.node, writerOptions); | ||
} | ||
else if (writerOptions.format === "map") { | ||
const writer = new writers_1.MapWriterImpl(this._options); | ||
return writer.serialize(this.as.node, writerOptions); | ||
return writer.serialize(this.node, writerOptions); | ||
} | ||
else if (writerOptions.format === "object") { | ||
const writer = new writers_1.ObjectWriterImpl(this._options); | ||
return writer.serialize(this.as.node, writerOptions); | ||
return writer.serialize(this.node, writerOptions); | ||
} | ||
else if (writerOptions.format === "json") { | ||
const writer = new writers_1.JSONWriterImpl(this._options); | ||
return writer.serialize(this.as.node, writerOptions); | ||
return writer.serialize(this.node, writerOptions); | ||
} | ||
@@ -558,3 +658,3 @@ else { | ||
const qName = dom_1.extractQName(name); | ||
const parent = this.as.node.parentNode; | ||
const parent = this.node.parentNode; | ||
if (parent) { | ||
@@ -566,3 +666,3 @@ namespace = parent.lookupNamespaceURI(qName[0]); | ||
if (attributes !== undefined) { | ||
for (let [attName, attValue] of util_1.forEachObject(attributes)) { | ||
util_1.forEachObject(attributes, (attName, attValue) => { | ||
if (attName === "xmlns") { | ||
@@ -577,6 +677,6 @@ namespace = attValue; | ||
} | ||
} | ||
}); | ||
} | ||
} | ||
const node = this.as.node; | ||
const node = this.node; | ||
const child = (namespace !== null && namespace !== undefined ? | ||
@@ -616,3 +716,3 @@ this._doc.createElementNS(namespace + "", name) : | ||
get _doc() { | ||
const node = this.as.node; | ||
const node = this.node; | ||
if (dom_1.isDocumentNode(node)) { | ||
@@ -635,4 +735,4 @@ return node; | ||
_debugInfo(name) { | ||
const node = this.as.node; | ||
const parentNode = this.as.node.parentNode; | ||
const node = this.node; | ||
const parentNode = node.parentNode; | ||
name = name || node.nodeName; | ||
@@ -639,0 +739,0 @@ const parentName = parentNode ? parentNode.nodeName : ''; |
@@ -54,2 +54,3 @@ "use strict"; | ||
const doc = domParser.parseFromString(contents, "text/xml"); | ||
dom_1.throwIfParserError(doc); | ||
builder = new builder_1.XMLBuilderImpl(doc); | ||
@@ -92,2 +93,3 @@ setOptions(doc, options); | ||
const doc = domParser.parseFromString("<TEMP_ROOT>" + contents + "</TEMP_ROOT>", "text/xml"); | ||
dom_1.throwIfParserError(doc); | ||
setOptions(doc, options); | ||
@@ -148,4 +150,4 @@ /* istanbul ignore next */ | ||
} | ||
function formatOptions(createOptions) { | ||
const options = util_1.applyDefaults(createOptions === undefined ? {} : createOptions, interfaces_1.DefaultBuilderOptions); | ||
function formatOptions(createOptions = {}) { | ||
const options = util_1.applyDefaults(createOptions, interfaces_1.DefaultBuilderOptions); | ||
if (options.convert.att.length === 0 || | ||
@@ -152,0 +154,0 @@ options.convert.ins.length === 0 || |
@@ -7,3 +7,2 @@ import { Node } from "@oozcitak/dom/lib/dom/interfaces"; | ||
private static _VoidElementNames; | ||
private _xmlVersion; | ||
private _docType?; | ||
@@ -31,6 +30,5 @@ private _comment?; | ||
* | ||
* @param xmlVersion - XML specification version | ||
* @param functions - serializer functions | ||
*/ | ||
constructor(xmlVersion: "1.0" | "1.1", functions: Partial<SerializerFunctions>); | ||
constructor(functions: Partial<SerializerFunctions>); | ||
/** | ||
@@ -37,0 +35,0 @@ * Produces an XML serialization of the given node. The pre-serializer inserts |
@@ -15,6 +15,5 @@ "use strict"; | ||
* | ||
* @param xmlVersion - XML specification version | ||
* @param functions - serializer functions | ||
*/ | ||
constructor(xmlVersion, functions) { | ||
constructor(functions) { | ||
/** | ||
@@ -24,3 +23,2 @@ * Returns the current depth of the XML tree. | ||
this.level = 0; | ||
this._xmlVersion = xmlVersion; | ||
this._docType = functions.docType; | ||
@@ -205,4 +203,6 @@ this._comment = functions.comment; | ||
/** 11.4. Append the value of qualified name to markup. */ | ||
/* istanbul ignore else */ | ||
if (this._beginElement) | ||
this._beginElement(qualifiedName); | ||
/* istanbul ignore else */ | ||
if (this._openTagBegin) | ||
@@ -276,4 +276,6 @@ this._openTagBegin(qualifiedName); | ||
*/ | ||
/* istanbul ignore else */ | ||
if (this._beginElement) | ||
this._beginElement(qualifiedName); | ||
/* istanbul ignore else */ | ||
if (this._openTagBegin) | ||
@@ -308,4 +310,6 @@ this._openTagBegin(qualifiedName); | ||
qualifiedName += prefix + ':' + node.localName; | ||
/* istanbul ignore else */ | ||
if (this._beginElement) | ||
this._beginElement(qualifiedName); | ||
/* istanbul ignore else */ | ||
if (this._openTagBegin) | ||
@@ -327,2 +331,3 @@ this._openTagBegin(qualifiedName); | ||
*/ | ||
/* istanbul ignore else */ | ||
if (this._attribute) | ||
@@ -368,4 +373,6 @@ this._attribute('xmlns:' + prefix, this._serializeAttributeValue(ns, requireWellFormed)); | ||
*/ | ||
/* istanbul ignore else */ | ||
if (this._beginElement) | ||
this._beginElement(qualifiedName); | ||
/* istanbul ignore else */ | ||
if (this._openTagBegin) | ||
@@ -386,2 +393,3 @@ this._openTagBegin(qualifiedName); | ||
*/ | ||
/* istanbul ignore else */ | ||
if (this._attribute) | ||
@@ -399,4 +407,6 @@ this._attribute('xmlns', this._serializeAttributeValue(ns, requireWellFormed)); | ||
inheritedNS = ns; | ||
/* istanbul ignore else */ | ||
if (this._beginElement) | ||
this._beginElement(qualifiedName); | ||
/* istanbul ignore else */ | ||
if (this._openTagBegin) | ||
@@ -430,4 +440,6 @@ this._openTagBegin(qualifiedName); | ||
PreSerializer._VoidElementNames.has(node.localName)) { | ||
/* istanbul ignore else */ | ||
if (this._endElement) | ||
this._endElement(qualifiedName); | ||
/* istanbul ignore else */ | ||
if (this._openTagEnd) | ||
@@ -438,4 +450,6 @@ this._openTagEnd(qualifiedName, true, true); | ||
else if (!isHTML && node.childNodes.length === 0) { | ||
/* istanbul ignore else */ | ||
if (this._endElement) | ||
this._endElement(qualifiedName); | ||
/* istanbul ignore else */ | ||
if (this._openTagEnd) | ||
@@ -446,2 +460,3 @@ this._openTagEnd(qualifiedName, true, false); | ||
else { | ||
/* istanbul ignore else */ | ||
if (this._openTagEnd) | ||
@@ -488,4 +503,6 @@ this._openTagEnd(qualifiedName, false, false); | ||
*/ | ||
/* istanbul ignore else */ | ||
if (this._endElement) | ||
this._endElement(qualifiedName); | ||
/* istanbul ignore else */ | ||
if (this._closeTag) | ||
@@ -545,3 +562,3 @@ this._closeTag(qualifiedName); | ||
*/ | ||
if (requireWellFormed && (!dom_1.isLegalChar(node.data, this._xmlVersion) || | ||
if (requireWellFormed && (!dom_1.isLegalChar(node.data) || | ||
node.data.indexOf("--") !== -1 || node.data.endsWith("-"))) { | ||
@@ -553,2 +570,3 @@ throw new Error("Comment data contains invalid characters (well-formed required)."); | ||
*/ | ||
/* istanbul ignore else */ | ||
if (this._comment) | ||
@@ -571,3 +589,3 @@ this._comment(node.data); | ||
*/ | ||
if (requireWellFormed && !dom_1.isLegalChar(node.data, this._xmlVersion)) { | ||
if (requireWellFormed && !dom_1.isLegalChar(node.data)) { | ||
throw new Error("Text data contains invalid characters (well-formed required)."); | ||
@@ -594,2 +612,3 @@ } | ||
} | ||
/* istanbul ignore else */ | ||
if (this._text) | ||
@@ -646,3 +665,3 @@ this._text(markup); | ||
if (requireWellFormed && | ||
(!dom_1.isLegalChar(node.systemId, this._xmlVersion) || | ||
(!dom_1.isLegalChar(node.systemId) || | ||
(node.systemId.indexOf('"') !== -1 && node.systemId.indexOf("'") !== -1))) { | ||
@@ -679,2 +698,3 @@ throw new Error("DocType system identifier contains invalid characters (well-formed required)."); | ||
*/ | ||
/* istanbul ignore else */ | ||
if (this._docType) | ||
@@ -706,3 +726,3 @@ this._docType(node.name, node.publicId, node.systemId); | ||
*/ | ||
if (requireWellFormed && (!dom_1.isLegalChar(node.data, this._xmlVersion) || | ||
if (requireWellFormed && (!dom_1.isLegalChar(node.data) || | ||
node.data.indexOf("?>") !== -1)) { | ||
@@ -720,2 +740,3 @@ throw new Error("Processing instruction data contains invalid characters (well-formed required)."); | ||
*/ | ||
/* istanbul ignore else */ | ||
if (this._instruction) | ||
@@ -734,2 +755,3 @@ this._instruction(node.target, node.data); | ||
} | ||
/* istanbul ignore else */ | ||
if (this._cdata) | ||
@@ -771,2 +793,3 @@ this._cdata(node.data); | ||
if (!requireWellFormed && attr.namespaceURI === null) { | ||
/* istanbul ignore else */ | ||
if (this._attribute) | ||
@@ -906,2 +929,3 @@ this._attribute(attr.localName, this._serializeAttributeValue(attr.value, requireWellFormed)); | ||
*/ | ||
/* istanbul ignore else */ | ||
if (this._attribute) | ||
@@ -942,2 +966,3 @@ this._attribute('xmlns:' + candidatePrefix, this._serializeAttributeValue(attributeNamespace, requireWellFormed)); | ||
attrName += attr.localName; | ||
/* istanbul ignore else */ | ||
if (this._attribute) | ||
@@ -1096,3 +1121,3 @@ this._attribute(attrName, this._serializeAttributeValue(attr.value, requireWellFormed)); | ||
*/ | ||
if (requireWellFormed && value !== null && !dom_1.isLegalChar(value, this._xmlVersion)) { | ||
if (requireWellFormed && value !== null && !dom_1.isLegalChar(value)) { | ||
throw new Error("Invalid characters in attribute value."); | ||
@@ -1099,0 +1124,0 @@ } |
@@ -72,3 +72,3 @@ "use strict"; | ||
let i = 0; | ||
for (const [key, val] of util_1.forEachObject(obj)) { | ||
util_1.forEachObject(obj, (key, val) => { | ||
if (isLeaf && options.prettyPrint) { | ||
@@ -89,3 +89,3 @@ markup += ' '; | ||
i++; | ||
} | ||
}, this); | ||
if (isLeaf && options.prettyPrint) { | ||
@@ -152,13 +152,8 @@ markup += ' '; | ||
*/ | ||
_descendantCount(obj, count) { | ||
count = count || 0; | ||
_descendantCount(obj, count = 0) { | ||
if (util_1.isArray(obj)) { | ||
for (const val of util_1.forEachArray(obj)) { | ||
count += this._descendantCount(val, count); | ||
} | ||
util_1.forEachArray(obj, val => count += this._descendantCount(val, count), this); | ||
} | ||
else if (util_1.isObject(obj)) { | ||
for (const [, val] of util_1.forEachObject(obj)) { | ||
count += this._descendantCount(val, count); | ||
} | ||
util_1.forEachObject(obj, (key, val) => count += this._descendantCount(val, count), this); | ||
} | ||
@@ -165,0 +160,0 @@ else { |
@@ -32,3 +32,3 @@ "use strict"; | ||
let listRegister = [currentList]; | ||
const pre = new PreSerializer_1.PreSerializer(this._builderOptions.version, { | ||
const pre = new PreSerializer_1.PreSerializer({ | ||
beginElement: (name) => { | ||
@@ -35,0 +35,0 @@ const childItems = this._addElement(currentList, name); |
@@ -42,3 +42,3 @@ "use strict"; | ||
this._refs = { suppressPretty: false, emptyNode: false, markup: "" }; | ||
this._pre = new PreSerializer_1.PreSerializer(this._builderOptions.version, { | ||
this._pre = new PreSerializer_1.PreSerializer({ | ||
docType: this._docType.bind(this), | ||
@@ -112,3 +112,4 @@ openTagBegin: this._openTagBegin.bind(this), | ||
let emptyNode = true; | ||
for (const childNode of this._pre.currentNode.childNodes) { | ||
let childNode = this._pre.currentNode.firstChild; | ||
while (childNode) { | ||
if (!dom_1.isTextNode(childNode)) { | ||
@@ -122,2 +123,3 @@ textOnlyNode = false; | ||
} | ||
childNode = childNode.nextSibling; | ||
} | ||
@@ -191,6 +193,3 @@ this._refs.suppressPretty = textOnlyNode; | ||
_beginLine() { | ||
if (!this._options.prettyPrint || this._refs.suppressPretty) { | ||
return; | ||
} | ||
else { | ||
if (this._options.prettyPrint && !this._refs.suppressPretty) { | ||
this._refs.markup += this._indent(this._options.offset + this._pre.level); | ||
@@ -204,6 +203,3 @@ } | ||
_endLine() { | ||
if (!this._options.prettyPrint || this._refs.suppressPretty) { | ||
return; | ||
} | ||
else { | ||
if (this._options.prettyPrint && !this._refs.suppressPretty) { | ||
this._refs.markup += this._options.newline; | ||
@@ -210,0 +206,0 @@ } |
{ | ||
"name": "xmlbuilder2", | ||
"version": "0.0.9", | ||
"version": "0.0.10", | ||
"keywords": [ | ||
@@ -28,4 +28,4 @@ "xml", | ||
"dependencies": { | ||
"@oozcitak/util": "4.0.0", | ||
"@oozcitak/dom": "1.7.1", | ||
"@oozcitak/util": "7.0.0", | ||
"@oozcitak/dom": "1.10.0", | ||
"@oozcitak/infra": "1.0.4" | ||
@@ -32,0 +32,0 @@ }, |
@@ -21,16 +21,25 @@ # xmlbuilder2 | ||
`xmlbuilder2` is a wrapper around DOM nodes which adds chainable functions to make it easier to create and work with XML documents. For example the following XML document: | ||
``` xml | ||
<?xml version="1.0"?> | ||
<root att="val"> | ||
<foo> | ||
<bar>foobar</bar> | ||
</foo> | ||
<baz/> | ||
</root> | ||
``` | ||
can be created with the following function chain: | ||
``` js | ||
const { document } = require('xmlbuilder2'); | ||
const root = document() | ||
.ele('topgun') | ||
.ele('pilots') | ||
.ele('pilot', { 'callsign': 'Iceman', 'rank': 'Lieutenant' }).txt('Tom Kazansky').up() | ||
.ele('pilot', { 'callsign': 'Maverick', 'rank': 'Lieutenant' }).txt('Pete Mitchell').up() | ||
.ele('pilot', { 'callsign': 'Goose', 'rank': 'Lieutenant (j.g.)' }).txt('Nick Bradshaw').up() | ||
const root = document({ version: '1.0' }) | ||
.ele('root', { att: 'val' }) | ||
.ele('foo') | ||
.ele('bar').txt('foobar').up() | ||
.up() | ||
.ele('hangar') | ||
.ele('aircraft').txt('F-14 Tomcat').up() | ||
.ele('aircraft').txt('MiG-28').up() | ||
.up() | ||
.ele('baz').up() | ||
.up(); | ||
@@ -42,18 +51,3 @@ | ||
``` | ||
will result in: | ||
``` xml | ||
<?xml version="1.0"?> | ||
<topgun> | ||
<pilots> | ||
<pilot callsign="Iceman" rank="Lieutenant">Tom Kazansky</pilot> | ||
<pilot callsign="Maverick" rank="Lieutenant">Pete Mitchell</pilot> | ||
<pilot callsign="Goose" rank="Lieutenant (j.g.)">Nick Bradshaw</pilot> | ||
</pilots> | ||
<hangar> | ||
<aircraft>F-14 Tomcat</aircraft> | ||
<aircraft>MiG-28</aircraft> | ||
</hangar> | ||
</topgun> | ||
``` | ||
___ | ||
@@ -67,15 +61,10 @@ | ||
const obj = { | ||
topgun: { | ||
pilots: { | ||
pilot: [ | ||
{ '@callsign': 'Iceman', '@rank': 'Lieutenant', '#': 'Tom Kazansky' }, | ||
{ '@callsign': 'Maverick', '@rank': 'Lieutenant', '#': 'Pete Mitchell' }, | ||
{ '@callsign': 'Goose', '@rank': 'Lieutenant (j.g.)', '#': 'Nick Bradshaw' } | ||
] | ||
root: { | ||
'@att': 'val', | ||
foo: { | ||
bar: 'foobar' | ||
}, | ||
hangar: { | ||
aircraft: ['F-14 Tomcat', 'MiG-28'] | ||
} | ||
baz: {} | ||
} | ||
} | ||
}; | ||
@@ -95,4 +84,4 @@ const doc = document(obj); | ||
// append a "baz" element to the root node of the document | ||
doc.root().ele("baz"); | ||
// append a 'baz' element to the root node of the document | ||
doc.root().ele('baz'); | ||
@@ -102,15 +91,7 @@ const xml = doc.end({ prettyPrint: true }); | ||
``` | ||
which would output: | ||
```xml | ||
<?xml version="1.0"?> | ||
<root att="val"> | ||
<foo> | ||
<bar>foobar</bar> | ||
</foo> | ||
<baz/> | ||
</root> | ||
``` | ||
or you could return a JS object by changing the `format` argument to `"object"`: | ||
which would output the same document string at the top of this page. | ||
Or you could return a JS object by changing the `format` argument to `'object'`: | ||
```js | ||
const obj = doc.end({ format: "object" }); | ||
const obj = doc.end({ format: 'object' }); | ||
console.log(obj); | ||
@@ -117,0 +98,0 @@ ``` |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
272700
48
5010
0
141
+ Added@oozcitak/dom@1.10.0(transitive)
+ Added@oozcitak/util@5.0.07.0.0(transitive)
- Removed@oozcitak/dom@1.7.1(transitive)
- Removed@oozcitak/util@4.0.0(transitive)
Updated@oozcitak/dom@1.10.0
Updated@oozcitak/util@7.0.0