@@ -262,8 +262,10 @@ export class Xslt {
262
262
node . transformedNodeName = name ;
263
263
264
264
domAppendTransformedChild ( context . outputNodeList [ context . outputPosition ] , node ) ;
265
+ // The element becomes the output node of the source node.
266
+ context . nodeList [ context . position ] . outputNode = node ;
265
267
const clonedContext = context . clone ( undefined , [ node ] , undefined , 0 ) ;
266
- await this . xsltChildNodes ( clonedContext , template , node ) ;
268
+ await this . xsltChildNodes ( clonedContext , template ) ;
267
269
break ;
268
270
case 'fallback' :
269
271
throw new Error ( `not implemented: ${ template . localName } ` ) ;
@@ -353,7 +355,7 @@ export class Xslt {
353
355
node = domCreateTransformedTextNode ( this . outputDocument , value ) ;
354
356
node . siblingPosition = context . nodeList [ context . position ] . siblingPosition ;
355
357
356
- if ( output . nodeType === DOM_DOCUMENT_FRAGMENT_NODE ) {
358
+ if ( output && output . nodeType === DOM_DOCUMENT_FRAGMENT_NODE ) {
357
359
output . appendTransformedChild ( node ) ;
358
360
} else {
359
361
context . outputNodeList [ context . outputPosition ] . appendTransformedChild ( node ) ;
@@ -471,7 +473,7 @@ export class Xslt {
471
473
await this . xsltChildNodes ( context , template , documentFragment ) ;
472
474
const value = xmlValue2 ( documentFragment ) ;
473
475
474
- if ( output . nodeType === DOM_DOCUMENT_FRAGMENT_NODE ) {
476
+ if ( output && output . nodeType === DOM_DOCUMENT_FRAGMENT_NODE ) {
475
477
domSetTransformedAttribute ( output , name , value ) ;
476
478
} else {
477
479
let sourceNode = context . nodeList [ context . position ] ;
@@ -507,15 +509,19 @@ export class Xslt {
507
509
508
510
// If the parent transformation is something like `xsl:element`, we should
509
511
// add a copy of the attribute to this element.
510
- domSetTransformedAttribute ( output , name , value ) ;
512
+ domSetTransformedAttribute ( outputNode , name , value ) ;
513
+
514
+ if ( sourceNode . nodeType === DOM_ATTRIBUTE_NODE ) {
515
+ sourceNode . transformedNodeType = DOM_ATTRIBUTE_NODE ;
516
+ sourceNode . transformedNodeName = name ;
517
+ sourceNode . transformedNodeValue = value ;
518
+ }
511
519
512
520
// Some operations start by the tag attributes, and not by the tag itself.
513
521
// When this is the case, the output node is not set yet, so
514
522
// we add the transformed attributes into the original tag.
515
523
if ( parentSourceNode && parentSourceNode . outputNode ) {
516
524
domSetTransformedAttribute ( parentSourceNode . outputNode , name , value ) ;
517
- } else {
518
- domSetTransformedAttribute ( parentSourceNode , name , value ) ;
519
525
}
520
526
}
521
527
}
@@ -527,7 +533,7 @@ export class Xslt {
527
533
* @param template The template.
528
534
* @param output The output. Only used if there's no corresponding output node already defined.
529
535
*/
530
- protected async xsltChoose ( context : ExprContext , template : XNode , output : XNode ) {
536
+ protected async xsltChoose ( context : ExprContext , template : XNode , output ? : XNode ) {
531
537
for ( const childNode of template . childNodes ) {
532
538
if ( childNode . nodeType !== DOM_ELEMENT_NODE ) {
533
539
continue ;
@@ -536,13 +542,11 @@ export class Xslt {
536
542
if ( this . isXsltElement ( childNode , 'when' ) ) {
537
543
const test = xmlGetAttribute ( childNode , 'test' ) ;
538
544
if ( this . xPath . xPathEval ( test , context ) . booleanValue ( ) ) {
539
- const outputNode = context . outputNodeList [ context . outputPosition ] || output ;
540
- await this . xsltChildNodes ( context , childNode , outputNode ) ;
545
+ await this . xsltChildNodes ( context , childNode , output ) ;
541
546
break ;
542
547
}
543
548
} else if ( this . isXsltElement ( childNode , 'otherwise' ) ) {
544
- const outputNode = context . outputNodeList [ context . outputPosition ] || output ;
545
- await this . xsltChildNodes ( context , childNode , outputNode ) ;
549
+ await this . xsltChildNodes ( context , childNode , output ) ;
546
550
break ;
547
551
}
548
552
}
@@ -740,9 +744,9 @@ export class Xslt {
740
744
741
745
const nonAttributeChildren = template . childNodes . filter ( ( n ) => n . nodeType !== DOM_ATTRIBUTE_NODE ) ;
742
746
if ( nonAttributeChildren . length > 0 ) {
743
- const root = domCreateDocumentFragment ( template . ownerDocument ) ;
744
- await this . xsltChildNodes ( context , template , root ) ;
745
- value = new NodeSetValue ( [ root ] ) ;
747
+ const fragment = domCreateDocumentFragment ( template . ownerDocument ) ;
748
+ await this . xsltChildNodes ( context , template , fragment ) ;
749
+ value = new NodeSetValue ( [ fragment ] ) ;
746
750
} else if ( select ) {
747
751
value = this . xPath . xPathEval ( select , context ) ;
748
752
} else {
@@ -785,7 +789,7 @@ export class Xslt {
785
789
* @param output The output.
786
790
*/
787
791
private commonLogicTextNode ( context : ExprContext , template : XNode , output : XNode ) {
788
- if ( output . nodeType === DOM_DOCUMENT_FRAGMENT_NODE ) {
792
+ if ( output && output . nodeType === DOM_DOCUMENT_FRAGMENT_NODE ) {
789
793
let node = domCreateTransformedTextNode ( this . outputDocument , template . nodeValue ) ;
790
794
domAppendTransformedChild ( output , node ) ;
791
795
} else {
@@ -843,7 +847,16 @@ export class Xslt {
843
847
newNode . transformedLocalName = template . localName ;
844
848
845
849
// The node can have transformed attributes from previous transformations.
846
- const transformedAttributes = node . transformedChildNodes . filter ( ( n ) => n . nodeType === DOM_ATTRIBUTE_NODE ) ;
850
+ // Case 1: attributes that were created by a transformation without a source attribute.
851
+ const transformedChildNodes = node . transformedChildNodes . filter ( ( n ) => n . nodeType === DOM_ATTRIBUTE_NODE ) ;
852
+ for ( const previouslyTransformedAttribute of transformedChildNodes ) {
853
+ const name = previouslyTransformedAttribute . transformedNodeName ;
854
+ const value = previouslyTransformedAttribute . transformedNodeValue ;
855
+ domSetTransformedAttribute ( newNode , name , value ) ;
856
+ }
857
+
858
+ // Case 2: attributes that existed as a source attribute and were transformed.
859
+ const transformedAttributes = node . childNodes . filter ( ( n ) => n . nodeType === DOM_ATTRIBUTE_NODE && n . transformedNodeName )
847
860
for ( const previouslyTransformedAttribute of transformedAttributes ) {
848
861
const name = previouslyTransformedAttribute . transformedNodeName ;
849
862
const value = previouslyTransformedAttribute . transformedNodeValue ;
@@ -864,7 +877,7 @@ export class Xslt {
864
877
outputNode . transformedChildNodes . length - 1 ,
865
878
++ elementContext . outputDepth
866
879
) ;
867
- await this . xsltChildNodes ( clonedContext , template , output ) ;
880
+ await this . xsltChildNodes ( clonedContext , template ) ;
868
881
} else {
869
882
// This applies also to the DOCUMENT_NODE of the XSL stylesheet,
870
883
// so we don't have to treat it specially.
0 commit comments