projects/wms-framework/src/lib/xml/xmlclasses.ts
Node for text
Properties |
constructor(value: string)
|
||||||||
Creates an instance of XText.
Parameters :
|
Public value |
Type : string
|
the text
|
parent |
Type : XContainer
|
Inherited from
XObject
|
Defined in
XObject:38
|
Parent of current element |
import { iuFirstOrDefault, iuOfType } from '../baseframework/collections';
import { XmlWriter } from '../baseframework/XmlWriter';
import { StringWriter } from '../helpers/StreamsSupport';
/**
* Base class for Xml objects
*
* @export
* @abstract
* @class XObject
* @wType System.Xml.Linq.XObject
* @wNetSupport
*/
export abstract class XObject {
/**
* Parent of current element
*
* @type {XContainer}
* @memberof XObject
* @wProperty Parent
*/
parent: XContainer;
}
/**
* Base class for Xml nodes
*
* @export
* @abstract
* @class XNode
* @extends {XObject}
* @wType System.Xml.Linq.XNode
* @wNetSupport
*/
export abstract class XNode extends XObject {}
/**
* Xml attributes
*
* @export
* @class XAttribute
* @extends {XObject}
* @wType System.Xml.Linq.XAttribute
* @wNetSupport
*/
export class XAttribute extends XObject {
/**
* Creates an instance of XAttribute.
* @param {string} Name attribute name
* @param {string} Value attribute value
* @memberof XAttribute
*/
constructor(public Name: string, public Value: string) {
super();
}
}
/**
* Node for text
*
* @export
* @class XText
* @extends {XNode}
* @wType System.Xml.Linq.XText
* @wNetSupport
*/
export class XText extends XNode {
/**
* Creates an instance of XText.
* @param {string} value the text
* @memberof XText
*/
constructor(public value: string) {
super();
}
}
/**
* Base class for containers
*
* @export
* @abstract
* @class XContainer
* @extends {XNode}
* @wType System.Xml.Linq.XContainer
* @wNetSupport
*/
export abstract class XContainer extends XNode {
/**
* Sequence of elements
*
* @protected
* @type {XNode[]}
* @memberof XContainer
*/
protected contents: XNode[] = [];
/**
* Initialize current element with the given node list
*
* @protected
* @param {{ length: number;[index: number]: Node }} elements
* @memberof XContainer
*/
protected initWith(elements: Iterable<Node>): void {
for (const e of elements) {
if (e.nodeType === 1 && e instanceof Element) {
const newElement = XElement.createFromDOMElement(e);
newElement.parent = this;
this.contents.push(newElement);
} else if (
e.nodeType == Node.TEXT_NODE &&
e.nodeValue &&
e.nodeValue.trim() !== ''
) {
const newElement = new XText(e.nodeValue);
newElement.parent = this;
this.contents.push(newElement);
}
}
}
/**
* Retrieves an element with the given name
*
* @param {string} elementName
* @return {*} {XElement}
* @memberof XContainer
* @wMethod Element
*/
public element(elementName: string): XElement {
for (const e of this.contents) {
if (e instanceof XElement && e.localName === elementName) {
return e;
}
}
return null;
}
/**
* Retrieves the sequence of elements
*
* @param {string} [elementName]
* @return {*} {Iterable<XElement>}
* @memberof XContainer
* @wMethod Elements
*/
public *elements(elementName?: string): Iterable<XElement> {
for (const e of this.contents) {
if (
e instanceof XElement &&
(typeof elementName === 'undefined' || e.localName === elementName)
) {
yield e;
}
}
}
/**
* Gets the sequence of child nodes
*
* @return {*} {Iterable<XNode>}
* @memberof XContainer
* @wMethod Nodes
*/
public nodes(): Iterable<XNode> {
return this.contents;
}
/**
* Removes the given child element
*
* @param {XElement} e
* @memberof XContainer
*/
public removeChildElement(e: XElement): void {
const idx = this.contents.indexOf(e);
if (idx !== -1) {
this.contents.splice(idx, 1);
}
}
/**
* Retrieves the descendants with the given name
*
* @param {string} [elementName]
* @return {*} {Iterable<XElement>}
* @memberof XContainer
*/
public *Descendants(elementName?: string): Iterable<XElement> {
if (elementName) {
yield* this.GetDescendantsByName(this, elementName);
}
}
/**
* Gets descendants by name
*
* @param {XContainer} container
* @param {string} elementName
* @return {*} {Iterable<XElement>}
* @memberof XContainer
* @wIgnore
*/
public *GetDescendantsByName(
container: XContainer,
elementName: string
): Iterable<XElement> {
for (const element of container.contents) {
if (element instanceof XElement) {
if (element.localName === elementName) {
yield element;
}
if (element.contents.length > 0) {
yield* this.GetDescendantsByName(element, elementName);
}
}
}
}
/**
* Adds child to the current element
*
* @param {object} content
* @memberof XContainer
*/
public Add(content: object): void {
if (content instanceof XNode) {
content.parent = this;
this.contents.push(content);
}
}
/**
* Get content array
*
* @return {*} {XNode[]}
* @memberof XContainer
*/
public getContents(): XNode[] {
return this.contents;
}
}
/**
* Xml document
*
* @export
* @class XDocument
* @extends {XContainer}
* @wType System.Xml.Linq.XDocument
* @wNetSupport
*/
export class XDocument extends XContainer {
/**
* Creates an instance of XDocument.
* @param {Document} doc
* @memberof XDocument
*/
constructor(doc: Document) {
super();
this.initWith([doc.documentElement]);
}
/**
* Parse XML document from an string
*
* @static
* @param {string} literalXml
* @return {*} {XDocument}
* @memberof XDocument
* @wMethod Parse
*/
public static parse(literalXml: string): XDocument {
const parser = new DOMParser();
const doc = parser.parseFromString(literalXml, 'text/xml');
return new XDocument(doc);
}
/**
* Converts the document to a string
*
* @return {*} {string}
* @memberof XDocument
*/
public toString(): string {
return serializeXNodeToString(this.contents[0]);
}
}
/**
* Xml element
*
* @export
* @class XElement
* @extends {XContainer}
* @wType System.Xml.Linq.XElement
* @wNetSupport
*/
export class XElement extends XContainer {
private attributes: { [name: string]: string } = {};
/**
* Creates an instance of XElement.
* @param {string} name
* @param {...unknown[]} contents
* @memberof XElement
*/
constructor(private name: string, ...contents: unknown[]) {
super();
for (const contentItem of contents) {
if (typeof contentItem === 'string') {
this.contents.push(new XText(contentItem));
} else if (contentItem instanceof XNode) {
this.contents.push(contentItem);
}
}
}
/**
* Get the local name
*
* @readonly
* @memberof XElement
*/
public get localName() {
return this.name;
}
/**
* Gets attribute sequence
*
* @return {*} {Iterable<XAttribute>}
* @memberof XElement
*/
public Attributes(): Iterable<XAttribute> {
const result: Array<XAttribute> = [];
for (const attName of Object.keys(this.attributes)) {
result.push(new XAttribute(attName, this.attributes[attName]));
}
return result;
}
/**
* Create XElement for DOM element
*
* @static
* @param {Element} e
* @return {*}
* @memberof XElement
*/
public static createFromDOMElement(e: Element) {
const result = new XElement(e.localName);
result.initWith(e.childNodes);
for (const att of e.attributes) {
result.attributes[att.name] = att.value;
}
return result;
}
/**
* Convert this element to a string
*
* @return {*} {string}
* @memberof XElement
*/
public toString(): string {
return serializeXNodeToString(this);
}
/**
* Remove current element from its parent
*
* @memberof XElement
* @wMethod Remove
*/
public remove() {
if (this.parent) {
this.parent.removeChildElement(this);
}
}
/**
* Gets the value of the current node
*
* @readonly
* @type {string}
* @memberof XElement
* @wProperty Value
*/
get value(): string {
const textNode = iuFirstOrDefault(iuOfType<XText>(this.contents, XText));
return textNode?.value ?? null;
}
/**
* Gets the value of the current node
*
* @memberof XElement
* @wProperty Value
*/
set value(newValue: string) {
const textNode = iuFirstOrDefault(iuOfType<XText>(this.contents, XText));
if (textNode) {
textNode.value = newValue;
} else {
this.contents.push(new XText(newValue));
}
}
}
/**
* Gets elements from sequence
*
* @export
* @param {Iterable<XElement>} sequence
* @param {string} [name]
* @return {*} {Iterable<XElement>}
*/
export function* xElementsFromSequence(
sequence: Iterable<XElement>,
name?: string
): Iterable<XElement> {
for (const e of sequence) {
for (const innerElement of e.elements(name)) {
yield innerElement;
}
}
}
/**
* Serialization XML step function
*
* @param {XNode} node
* @param {XmlWriter} writer
*/
const serializingXNodeToString = (node: XNode, writer: XmlWriter) => {
if (node instanceof XElement) {
writer.WriteStartElement(node.localName);
for (const att of node.Attributes()) {
writer.WriteAttributeString(att.Name, att.Value);
}
for (const child of node.nodes()) {
serializingXNodeToString(child, writer);
}
writer.WriteEndElement();
} else if (node instanceof XText) {
writer.WriteValue(node.value);
}
};
/**
* Entry point for XML serialization
*
* @param {XNode} node
* @return {*}
*/
const serializeXNodeToString = (node: XNode) => {
const buffer = new StringWriter();
const writer = XmlWriter.Create(buffer);
serializingXNodeToString(node, writer);
return buffer.toString();
};
/**
* Removes all specified elements from its parent node
*
* @export
* @template T
* @param {Iterable<T>} sequence
*/
export function xRemoveElementsFromSequence<T extends XNode>(
sequence: Iterable<T>
): void {
for (const obj of sequence) {
if (obj instanceof XElement) {
obj.remove();
}
}
}