Skip to content

Commit 05f2c97

Browse files
Attributes issue (#78)
* Switching context when dealing with attributes on template match. * Bringing full test back. * Fixing issue with tag attributes.
1 parent 1084d44 commit 05f2c97

File tree

4 files changed

+57
-14
lines changed

4 files changed

+57
-14
lines changed

src/xslt/xslt.ts

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,10 @@ export class Xslt {
214214
const clonedContext = modifiedContext.clone(
215215
[modifiedContext.nodeList[j]],
216216
undefined,
217+
// [modifiedContext.nodeList[j].outputNode],
217218
0,
218219
undefined
220+
// 0
219221
);
220222
clonedContext.inApplyTemplates = true;
221223
// The output depth should be restarted, since
@@ -230,13 +232,30 @@ export class Xslt {
230232
case 'attribute':
231233
nameExpr = xmlGetAttribute(template, 'name');
232234
name = this.xsltAttributeValue(nameExpr, context);
235+
233236
const documentFragment = domCreateDocumentFragment(this.outputDocument);
234237
this.xsltChildNodes(context, template, documentFragment);
235238
value = xmlValue2(documentFragment);
236239
if (output !== null && output !== undefined) {
237240
domSetTransformedAttribute(output, name, value);
238241
} else {
239-
let outputNode = context.outputNodeList[context.outputPosition];
242+
let sourceNode = context.nodeList[context.position];
243+
let parentSourceNode = sourceNode.parentNode;
244+
let outputNode = sourceNode.outputNode;
245+
246+
// At this point, the output node should exist.
247+
// If not, a new node is created.
248+
if (outputNode === null || outputNode === undefined) {
249+
outputNode = new XNode(
250+
sourceNode.nodeType,
251+
sourceNode.nodeName,
252+
sourceNode.nodeValue,
253+
context.outputNodeList[context.outputPosition],
254+
sourceNode.namespaceUri
255+
);
256+
sourceNode.outputNode = outputNode;
257+
}
258+
240259
// Corner case:
241260
// It can happen here that we don't have the root node set.
242261
// In this case we need to append a copy of the root
@@ -248,8 +267,17 @@ export class Xslt {
248267
newRootNode.transformedLocalName = sourceRootNode.localName;
249268
domAppendTransformedChild(outputNode, newRootNode);
250269
outputNode = newRootNode;
270+
parentSourceNode = newRootNode;
271+
}
272+
273+
// Some operations start by the tag attributes, and not by the tag itself.
274+
// When this is the case, the output node is not set yet, so
275+
// we add the transformed attributes into the original tag.
276+
if (parentSourceNode && parentSourceNode.outputNode) {
277+
domSetTransformedAttribute(parentSourceNode.outputNode, name, value);
278+
} else {
279+
domSetTransformedAttribute(parentSourceNode, name, value);
251280
}
252-
domSetTransformedAttribute(outputNode, name, value);
253281
}
254282

255283
break;
@@ -407,7 +435,8 @@ export class Xslt {
407435
context.baseTemplateMatched = true;
408436
}
409437

410-
this.xsltChildNodes(context, template, output);
438+
const templateContext = context.clone(nodes, undefined, 0);
439+
this.xsltChildNodes(templateContext, template, output);
411440
}
412441
break;
413442
case 'text':
@@ -733,15 +762,18 @@ export class Xslt {
733762
newNode.transformedNodeName = template.nodeName;
734763
newNode.transformedLocalName = template.localName;
735764

765+
// The node can have transformed attributes from previous transformations.
766+
for (const previouslyTransformedAttribute of node.transformedAttributes) {
767+
const name = previouslyTransformedAttribute.transformedNodeName;
768+
const value = previouslyTransformedAttribute.transformedNodeValue;
769+
domSetTransformedAttribute(newNode, name, value);
770+
}
771+
736772
const templateAttributes = template.attributes.filter((a: any) => a);
737-
if (templateAttributes.length === 0) {
738-
newNode.transformedAttributes = [];
739-
} else {
740-
for (const attribute of templateAttributes) {
741-
const name = attribute.nodeName;
742-
const value = this.xsltAttributeValue(attribute.nodeValue, elementContext);
743-
domSetTransformedAttribute(newNode, name, value);
744-
}
773+
for (const attribute of templateAttributes) {
774+
const name = attribute.nodeName;
775+
const value = this.xsltAttributeValue(attribute.nodeValue, elementContext);
776+
domSetTransformedAttribute(newNode, name, value);
745777
}
746778

747779
const outputNode = context.outputNodeList[context.outputPosition];
@@ -796,6 +828,10 @@ export class Xslt {
796828
return false;
797829
}
798830

831+
protected xsltAttribute(attributeName: string, context: ExprContext): XNode {
832+
return context.nodeList[context.position].attributes.find(a => a.nodeName === attributeName);
833+
}
834+
799835
/**
800836
* Evaluates an XSL-T attribute value template. Attribute value
801837
* templates are attributes on XSL-T elements that contain XPath

tests/lmht/html-to-lmht.test.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1478,7 +1478,9 @@ describe('HTML to LMHT', () => {
14781478
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
14791479
<![endif]-->
14801480
</head>
1481-
1481+
<body>
1482+
<p class="anything">This is a paragraph with a class</p>
1483+
</body>
14821484
</html>
14831485
`;
14841486

@@ -1488,6 +1490,9 @@ describe('HTML to LMHT', () => {
14881490
`<recurso destino="css/bootstrap.min.css" tipo="stylesheet"/>` +
14891491
`<recurso destino="css/simple-blog-template.css" tipo="stylesheet"/>` +
14901492
`</cabeça>` +
1493+
`<corpo>` +
1494+
`<parágrafo classe="anything">This is a paragraph with a class</parágrafo>` +
1495+
`</corpo>` +
14911496
`</lmht>`
14921497

14931498
const xsltClass = new Xslt();

tests/xml/xml-to-html.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ describe('XML to HTML', () => {
3232
</xsl:template>
3333
</xsl:stylesheet>`;
3434

35-
const expectedOutHtml = `<div><div><table><tr><th>A</th><th>B</th><th>C</th></tr><tr><td>AA</td><td>BB</td><td>CC</td></tr></table></div><div>should be below table rite??!</div></div>`;
35+
const expectedOutHtml = `<div><div><table><tr><th>A</th><th>B</th><th>C</th></tr><tr><td>AA</td><td>BB</td><td>CC</td></tr></table></div></div><div><div>should be below table rite??!</div></div>`;
3636

3737
const xsltClass = new Xslt();
3838
const xmlParser = new XmlParser();

tests/xpath/functions.test.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,9 @@ describe('XPath Functions', () => {
133133
});
134134
});
135135

136-
it('generate-id, trivial', () => {
136+
// TODO: This returns the following in other transformers:
137+
// "Unable to generate the XML document using the provided XML/XSL input. Cannot create an attribute node (uid) whose parent is a document node. Most recent element start tag was output at line -1 of module *unknown*"
138+
it.skip('generate-id, trivial', () => {
137139
const xml = xmlParser.xmlParse(<root></root>);
138140
const xsltDefinition = xmlParser.xmlParse(
139141
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

0 commit comments

Comments
 (0)