Skip to content

Commit

Permalink
Unifying attributes with other child nodes. (#84)
Browse files Browse the repository at this point in the history
* Unifying attributes with the rest of child nodes.
* Refactoring `Xslt` class.
* Refactoring `xml-functions` and `xml-parser` to use child nodes as attributes.
* `xmlValue` should not consider attributes.
* Fixing unit tests that were using `attributes` property to assert results.
* Getting rid of `transformedAttributes`.
* The XML output should *not* consider attributes for determine whether tags should be self-closed or not.
* - Improving types among different sources;
- Fixing xPath expressions to not consider attributes for most of cases.
* - Even more types;
- Changing `xsltVariable` to not consider attributes while deciding how to set the `NodeValue` object.
* Fixing typing for `PredicateExpr`.
  • Loading branch information
leonelsanchesdasilva authored Jan 29, 2024
1 parent 4b4afc5 commit b9b64d1
Show file tree
Hide file tree
Showing 19 changed files with 291 additions and 188 deletions.
2 changes: 1 addition & 1 deletion src/dom/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { XDocument } from "./xdocument";
import { XNode } from './xnode';

// Wrapper around DOM methods so we can condense their invocations.
export function domGetAttributeValue(node: any, name: string) {
export function domGetAttributeValue(node: XNode, name: string) {
return node.getAttributeValue(name);
}

Expand Down
5 changes: 3 additions & 2 deletions src/dom/xdocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ export class XDocument extends XNode {
this.documentElement = null;
}

clear() {
// TODO: Do we still need this?
/* clear() {
XNode.recycle(this.documentElement);
this.documentElement = null;
}
} */

appendChild(node: any) {
super.appendChild(node);
Expand Down
44 changes: 30 additions & 14 deletions src/dom/xml-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { XmlOutputOptions } from './xml-output-options';
* @param disallowBrowserSpecificOptimization A boolean, to avoid browser optimization.
* @returns The XML value as a string.
*/
export function xmlValue(node: any, disallowBrowserSpecificOptimization: boolean = false): string {
export function xmlValue(node: XNode | any, disallowBrowserSpecificOptimization: boolean = false): string {
if (!node) {
return '';
}
Expand All @@ -42,25 +42,28 @@ export function xmlValue(node: any, disallowBrowserSpecificOptimization: boolean
case DOM_DOCUMENT_NODE:
case DOM_DOCUMENT_FRAGMENT_NODE:
if (!disallowBrowserSpecificOptimization) {
// IE, Safari, Opera, and friends
// Only returns something if node has either `innerText` or `textContent` (not an XNode).
// IE, Safari, Opera, and friends (`innerText`)
const innerText = node.innerText;
if (innerText != undefined) {
return innerText;
}
// Firefox
// Firefox (`textContent`)
const textContent = node.textContent;
if (textContent != undefined) {
return textContent;
}
}

if (node.transformedChildNodes.length > 0) {
for (let i = 0; i < node.transformedChildNodes.length; ++i) {
ret += xmlValue(node.transformedChildNodes[i]);
const transformedTextNodes = node.transformedChildNodes.filter((n: XNode) => n.nodeType !== DOM_ATTRIBUTE_NODE);
for (let i = 0; i < transformedTextNodes.length; ++i) {
ret += xmlValue(transformedTextNodes[i]);
}
} else {
for (let i = 0; i < node.childNodes.length; ++i) {
ret += xmlValue(node.childNodes[i]);
const textNodes = node.childNodes.filter((n: XNode) => n.nodeType !== DOM_ATTRIBUTE_NODE);
for (let i = 0; i < textNodes.length; ++i) {
ret += xmlValue(textNodes[i]);
}
}

Expand Down Expand Up @@ -96,7 +99,7 @@ export function xmlValue2(node: any, disallowBrowserSpecificOptimization: boolea
return textContent;
}
}
// pobrecito!

const len = node.transformedChildNodes.length;
for (let i = 0; i < len; ++i) {
ret += xmlValue(node.transformedChildNodes[i]);
Expand Down Expand Up @@ -137,10 +140,15 @@ function xmlTextRecursive(node: XNode, buffer: string[], options: XmlOutputOptio
buffer.push(`<!--${node.nodeValue}-->`);
} else if (node.nodeType == DOM_ELEMENT_NODE) {
buffer.push(`<${xmlFullNodeName(node)}`);
for (let i = 0; i < node.attributes.length; ++i) {
const a = node.attributes[i];
if (a && a.nodeName && a.nodeValue) {
buffer.push(` ${xmlFullNodeName(a)}="${xmlEscapeAttr(a.nodeValue)}"`);

for (let i = 0; i < node.childNodes.length; ++i) {
const childNode = node.childNodes[i];
if (!childNode || childNode.nodeType !== DOM_ATTRIBUTE_NODE) {
continue;
}

if (childNode.nodeName && childNode.nodeValue) {
buffer.push(` ${xmlFullNodeName(childNode)}="${xmlEscapeAttr(childNode.nodeValue)}"`);
}
}

Expand Down Expand Up @@ -233,7 +241,11 @@ function xmlTransformedTextRecursive(node: XNode, buffer: any[], options: XmlOut
function xmlElementLogicTrivial(node: XNode, buffer: string[], options: XmlOutputOptions) {
buffer.push(`<${xmlFullNodeName(node)}`);

const attributes = node.transformedAttributes || node.attributes;
let attributes = node.transformedChildNodes.filter(n => n.nodeType === DOM_ATTRIBUTE_NODE);
if (attributes.length === 0) {
attributes = node.childNodes.filter(n => n.nodeType === DOM_ATTRIBUTE_NODE);
}

for (let i = 0; i < attributes.length; ++i) {
const attribute = attributes[i];
if (!attribute) {
Expand All @@ -245,7 +257,11 @@ function xmlElementLogicTrivial(node: XNode, buffer: string[], options: XmlOutpu
}
}

let childNodes = node.transformedChildNodes.length > 0 ? node.transformedChildNodes : node.childNodes;
let childNodes = node.transformedChildNodes.filter(n => n.nodeType !== DOM_ATTRIBUTE_NODE);
if (childNodes.length === 0) {
childNodes = node.childNodes.filter(n => n.nodeType !== DOM_ATTRIBUTE_NODE);
}

childNodes = childNodes.sort((a, b) => a.siblingPosition - b.siblingPosition);
if (childNodes.length === 0) {
if (options.outputMethod === 'html' && ['hr', 'link', 'meta'].includes(node.nodeName)) {
Expand Down
32 changes: 21 additions & 11 deletions src/dom/xml-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
XML11_VERSION_INFO
} from './xmltoken';
import { XNode } from './xnode';
import { DOM_ATTRIBUTE_NODE } from '../constants';

/**
* Original author: Steffen Meschkat <[email protected]> (the `xmlParse` function,
Expand Down Expand Up @@ -67,12 +68,17 @@ export class XmlParser {
};
let n = node;
while (n !== null) {
for (let i = 0; i < n.attributes.length; i++) {
if (n.attributes[i].nodeName.startsWith('xmlns:')) {
const prefix = n.attributes[i].nodeName.split(':')[1];
if (!(prefix in map)) map[prefix] = n.attributes[i].nodeValue;
} else if (n.attributes[i].nodeName == 'xmlns') {
if (!('' in map)) map[''] = n.attributes[i].nodeValue || null;
for (let i = 0; i < n.childNodes.length; i++) {
const childNode = n.childNodes[i];
if (childNode.nodeType !== DOM_ATTRIBUTE_NODE) {
continue;
}

if (childNode.nodeName.startsWith('xmlns:')) {
const prefix = childNode.nodeName.split(':')[1];
if (!(prefix in map)) map[prefix] = childNode.nodeValue;
} else if (childNode.nodeName == 'xmlns') {
if (!('' in map)) map[''] = childNode.nodeValue || null;
}
}
n = n.parentNode;
Expand Down Expand Up @@ -258,11 +264,15 @@ export class XmlParser {
} else {
if ('' in namespaceMap) node.namespaceUri = namespaceMap[''];
}
for (let i = 0; i < node.attributes.length; ++i) {
if (node.attributes[i].prefix !== null) {
if (node.attributes[i].prefix in namespaceMap) {
node.attributes[i].namespaceUri = namespaceMap[node.attributes[i].prefix];
}

for (let i = 0; i < node.childNodes.length; ++i) {
const childNode = node.childNodes[i];
if (childNode.nodeType !== DOM_ATTRIBUTE_NODE) {
continue;
}

if (childNode.prefix !== null && childNode.prefix in namespaceMap) {
childNode.namespaceUri = namespaceMap[childNode.prefix];
// else, prefix undefined.
}
// elements with no prefix always have no namespace, so do nothing here.
Expand Down
Loading

0 comments on commit b9b64d1

Please sign in to comment.