Skip to content

Commit 157c9c8

Browse files
Expanding the logic to write correct LMHT output.
1 parent 1971175 commit 157c9c8

File tree

3 files changed

+79
-53
lines changed

3 files changed

+79
-53
lines changed

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"runtimeArgs": [
1212
"--inspect-brk",
1313
"${workspaceRoot}/node_modules/jest/bin/jest.js",
14-
// "local-name.test",
14+
// "lmht.test",
1515
"--runInBand"
1616
],
1717
"skipFiles": ["<node_internals>/**", "node_modules/**"],

src/xslt/xslt.ts

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,12 @@ export class Xslt {
126126
}
127127

128128
this.xsltProcessContext(expressionContext, stylesheet, outputDocument);
129-
const ret = xmlTransformedText(outputDocument, {
129+
const transformedOutputXml = xmlTransformedText(outputDocument, {
130130
cData: false,
131131
escape: this.options.escape,
132132
selfClosingTags: this.options.selfClosingTags
133133
});
134-
return ret;
134+
return transformedOutputXml;
135135
}
136136

137137
/**
@@ -202,17 +202,25 @@ export class Xslt {
202202
const modifiedContext = context.clone(nodes);
203203
for (let i = 0; i < templates.length; ++i) {
204204
for (let j = 0; j < modifiedContext.contextSize(); ++j) {
205-
const clonedContext = modifiedContext.clone(
206-
[modifiedContext.nodeList[j]],
207-
undefined,
208-
0,
209-
undefined
210-
);
211-
clonedContext.inApplyTemplates = true;
212-
// The output depth should be restarted, since
213-
// another template is being applied from this point.
214-
clonedContext.outputDepth = 0;
215-
this.xsltProcessContext(clonedContext, templates[i], output);
205+
// If the current node is text, there's no need to test all the templates
206+
// against it. Just appending it to its parent is fine.
207+
if (modifiedContext.nodeList[j].nodeType === DOM_TEXT_NODE) {
208+
const textNodeContext = context.clone([modifiedContext.nodeList[j]], undefined, 0, undefined);
209+
// TODO: verify if it is okay to pass the own text node as template.
210+
this.commonLogicTextNode(textNodeContext, modifiedContext.nodeList[j]);
211+
} else {
212+
const clonedContext = modifiedContext.clone(
213+
[modifiedContext.nodeList[j]],
214+
undefined,
215+
0,
216+
undefined
217+
);
218+
clonedContext.inApplyTemplates = true;
219+
// The output depth should be restarted, since
220+
// another template is being applied from this point.
221+
clonedContext.outputDepth = 0;
222+
this.xsltProcessContext(clonedContext, templates[i], output);
223+
}
216224
}
217225
}
218226

@@ -522,24 +530,6 @@ export class Xslt {
522530
for (let i = 0; i < sortContext.contextSize(); ++i) {
523531
this.xsltChildNodes(sortContext.clone(sortContext.nodeList, undefined, i), template, output);
524532
}
525-
// TODO: group nodes by parent node.
526-
// const nodeGroups = this.groupBy(nodes, 'parentNode');
527-
528-
/* for (let [group, _nodes] of Object.entries(nodeGroups)) {
529-
const sortContext = context.clone(_nodes, 0);
530-
this.xsltSort(sortContext, template);
531-
532-
for (let i = 0; i < sortContext.contextSize(); ++i) {
533-
this.xsltChildNodes(sortContext.clone(sortContext.nodeList, i), template, output);
534-
}
535-
} */
536-
}
537-
538-
protected groupBy(xs: any, key: any) {
539-
return xs.reduce((rv, x) => {
540-
(rv[x[key]] = rv[x[key]] || []).push(x);
541-
return rv;
542-
}, {});
543533
}
544534

545535
/**
@@ -654,6 +644,28 @@ export class Xslt {
654644
}
655645
}
656646

647+
/**
648+
* This logic is used in two different places:
649+
* - `xsltPassThrough`, if the template asks this library to write a text node;
650+
* - `xsltProcessContext`, `apply-templates` operation, when the current node is text.
651+
* @param context The Expression Context.
652+
* @param template The template, that contains the node value to be written.
653+
*/
654+
private commonLogicTextNode(context: ExprContext, template: XNode) {
655+
const textNodeList = context.outputNodeList[context.outputPosition].transformedChildNodes.filter(
656+
(n) => n.nodeType === DOM_TEXT_NODE
657+
);
658+
659+
if (textNodeList.length > 0) {
660+
let node = textNodeList[0];
661+
node.transformedNodeValue = template.nodeValue;
662+
} else {
663+
let node = domCreateTransformedTextNode(this.outputDocument, template.nodeValue);
664+
node.transformedParentNode = context.outputNodeList[context.outputPosition];
665+
domAppendTransformedChild(context.outputNodeList[context.outputPosition], node);
666+
}
667+
}
668+
657669
/**
658670
* Passes template text to the output. The current template node does
659671
* not specify an XSL-T operation and therefore is appended to the
@@ -666,22 +678,10 @@ export class Xslt {
666678
protected xsltPassThrough(context: ExprContext, template: XNode, output: XNode) {
667679
if (template.nodeType == DOM_TEXT_NODE) {
668680
if (this.xsltPassText(template)) {
669-
const textNodeList = context.outputNodeList[context.outputPosition].transformedChildNodes.filter(
670-
(n) => n.nodeType === DOM_TEXT_NODE
671-
);
672-
673-
if (textNodeList.length > 0) {
674-
let node = textNodeList[0];
675-
node.transformedNodeValue = template.nodeValue;
676-
} else {
677-
let node = domCreateTransformedTextNode(this.outputDocument, template.nodeValue);
678-
node.transformedParentNode = context.outputNodeList[context.outputPosition];
679-
domAppendTransformedChild(context.outputNodeList[context.outputPosition], node);
680-
}
681+
this.commonLogicTextNode(context, template);
681682
}
682683
} else if (template.nodeType == DOM_ELEMENT_NODE) {
683684
let node: XNode;
684-
// let node = domCreateElement(outputDocument, template.nodeName);
685685
let elementContext = context;
686686
if (context.nodeList[context.position].nodeName === '#document') {
687687
node = context.nodeList[context.position].firstChild;

tests/lmht.test.tsx

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,43 @@ describe('LMHT', () => {
2424
const xsltString =
2525
'<?xml version="1.0"?>' +
2626
(
27-
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
28-
<xsl:template match="/lmht">
29-
<html>
30-
Teste
31-
</html>
32-
</xsl:template>
33-
</xsl:stylesheet>
27+
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
28+
<xsl:output method="html" version="5.0" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
29+
30+
<xsl:template match="/lmht">
31+
<html>
32+
<xsl:apply-templates select="node()" />
33+
</html>
34+
</xsl:template>
35+
36+
<xsl:template match="/lmht/cabeca|/lmht/cabeça">
37+
<head>
38+
<xsl:apply-templates select="@*|node()" />
39+
</head>
40+
</xsl:template>
41+
<xsl:template match="/lmht/cabeca/titulo|/lmht/cabeca/título|/lmht/cabeça/titulo|/lmht/cabeça/título">
42+
<title>
43+
<xsl:apply-templates select="@*|node()" />
44+
</title>
45+
</xsl:template>
46+
47+
<xsl:template match="/lmht/corpo">
48+
<body>
49+
<xsl:apply-templates select="@*|node()" />
50+
</body>
51+
</xsl:template>
52+
</xsl:transform>
3453
);
3554

3655
const expectedOutString = (
37-
<html>Teste</html>
56+
<html>
57+
<head>
58+
<title>Teste</title>
59+
</head>
60+
<body>
61+
Teste
62+
</body>
63+
</html>
3864
);
3965

4066
const xsltClass = new Xslt();

0 commit comments

Comments
 (0)