@@ -5,11 +5,39 @@ import XRegExp = require('xregexp');
55
66export class XmlPatcher implements patch . IPatcher {
77 constructor (
8- private patches : patch . IPatch [ ] ,
8+ public patches : patch . IPatch [ ] ,
99 private namespaces : { [ tag : string ] : string }
1010 ) {
1111 }
1212
13+ detectArrayOperation ( path : string ) : { path : string , isArrayOperation : boolean , append ?: boolean , index ?: number } {
14+ var lastSlash = path . lastIndexOf ( '/' ) ;
15+ var lastFragment = path . substr ( lastSlash + 1 ) ;
16+ var remainingPath = path . substr ( 0 , lastSlash ) ;
17+
18+ if ( lastFragment == '-' ) {
19+ return {
20+ path : remainingPath ,
21+ isArrayOperation : true ,
22+ append : true
23+ } ;
24+ }
25+
26+ var isLastFragmentDigitOnly : string [ ] = XRegExp . match ( lastFragment , / ^ \d + $ / g) ;
27+ if ( isLastFragmentDigitOnly . length > 0 ) {
28+ return {
29+ path : remainingPath ,
30+ isArrayOperation : true ,
31+ index : parseInt ( lastFragment )
32+ } ;
33+ }
34+
35+ return {
36+ path : path ,
37+ isArrayOperation : false
38+ } ;
39+ }
40+
1341 getParentPath ( path : string ) : { path : string , nodeName : string , isAttribute : boolean } {
1442 var lastSlash = path . lastIndexOf ( '/' ) ;
1543 var nodeName = path . substr ( lastSlash + 1 ) ;
@@ -26,12 +54,30 @@ export class XmlPatcher implements patch.IPatcher {
2654 return false ;
2755 }
2856
57+ notsupported ( patch : patch . IPatch ) : boolean {
58+ console . log ( "operation not supported: " + patch . op + " " + patch . path ) ;
59+ return false ;
60+ }
61+
2962 remove ( xml : Document , select : any , patch : patch . IPatch ) : boolean {
63+ var arrayOperation = this . detectArrayOperation ( patch . path ) ;
64+ if ( arrayOperation . isArrayOperation ) {
65+ if ( arrayOperation . append ) {
66+ var node = < SVGSVGElement > select ( arrayOperation . path , xml , true ) ;
67+ node . removeChild ( node . lastChild ) ;
68+ return true ;
69+ } else {
70+ var node = < SVGSVGElement > select ( arrayOperation . path , xml , true ) ;
71+ node . removeChild ( node . childNodes [ arrayOperation . index ] ) ;
72+ return true ;
73+ }
74+ }
75+
3076 var node = < SVGSVGElement > select ( patch . path , xml , true ) ;
3177 if ( node ) {
3278 var parentPath = this . getParentPath ( patch . path ) ;
3379 var parentNode = < SVGSVGElement > select ( parentPath . path , xml , true ) ;
34- if ( parentPath . isAttribute ) {
80+ if ( parentPath . isAttribute ) {
3581 parentNode . removeAttribute ( parentPath . nodeName ) ;
3682 } else {
3783 node . parentNode . removeChild ( node ) ;
@@ -43,14 +89,20 @@ export class XmlPatcher implements patch.IPatcher {
4389 }
4490
4591 move ( xml : Document , select : any , patch : patch . IPatch ) : boolean {
46- var fromNode = < SVGSVGElement > select ( patch . from , xml , true ) ;
47- var toNode = < SVGSVGElement > select ( patch . path , xml , true ) ;
48- if ( fromNode ) {
49- patch . value = fromNode . textContent ;
50- this . remove ( xml , select , { op : 'remove' , path : patch . from } ) ;
51- return this . replace ( xml , select , patch ) ;
92+ var arrayOperation = this . detectArrayOperation ( patch . path ) ;
93+ var arrayOperationFrom = this . detectArrayOperation ( patch . from ) ;
94+ if ( arrayOperation . isArrayOperation || arrayOperationFrom . isArrayOperation ) {
95+ return this . notsupported ( patch ) ;
5296 } else {
53- return this . notfound ( patch ) ;
97+ var fromNode = < SVGSVGElement > select ( patch . from , xml , true ) ;
98+ var toNode = < SVGSVGElement > select ( patch . path , xml , true ) ;
99+ if ( fromNode ) {
100+ patch . value = fromNode . textContent ;
101+ this . remove ( xml , select , { op : 'remove' , path : patch . from } ) ;
102+ return this . replace ( xml , select , patch ) ;
103+ } else {
104+ return this . notfound ( patch ) ;
105+ }
54106 }
55107 }
56108
@@ -66,6 +118,21 @@ export class XmlPatcher implements patch.IPatcher {
66118 }
67119
68120 add ( xml : Document , select : any , patch : patch . IPatch ) : boolean {
121+ var arrayOperation = this . detectArrayOperation ( patch . path ) ;
122+ if ( arrayOperation . isArrayOperation ) {
123+ if ( arrayOperation . append ) {
124+ var node = < SVGSVGElement > select ( arrayOperation . path , xml , true ) ;
125+ var newNode = < HTMLElement > xml . createElement ( patch . value ) ;
126+ node . appendChild ( newNode ) ;
127+ return true ;
128+ } else {
129+ var node = < SVGSVGElement > select ( arrayOperation . path , xml , true ) ;
130+ var newNode = < HTMLElement > xml . createElement ( patch . value ) ;
131+ node . insertBefore ( newNode , node . childNodes [ arrayOperation . index ] )
132+ return true ;
133+ }
134+ }
135+
69136 var node = < SVGSVGElement > select ( patch . path , xml , true ) ;
70137 if ( node ) {
71138 node . textContent = patch . value ;
@@ -92,18 +159,28 @@ export class XmlPatcher implements patch.IPatcher {
92159 }
93160
94161 replace ( xml : Document , select : any , patch : patch . IPatch ) : boolean {
95- var node = < SVGSVGElement > select ( patch . path , xml , true ) ;
96- if ( node ) {
97- var parentPath = this . getParentPath ( patch . path ) ;
98- var parentNode = < SVGSVGElement > select ( parentPath . path , xml , true ) ;
99- if ( parentPath . isAttribute ) {
100- parentNode . setAttribute ( parentPath . nodeName , patch . value ) ;
101- } else {
102- node . textContent = patch . value ;
103- }
162+ var arrayOperation = this . detectArrayOperation ( patch . path ) ;
163+ if ( arrayOperation . isArrayOperation ) {
164+ var node = < SVGSVGElement > select ( arrayOperation . path , xml , true ) ;
165+ var childNode = node . childNodes [ arrayOperation . index ] ;
166+ var newNode = < HTMLElement > xml . createElement ( patch . value ) ;
167+ node . insertBefore ( newNode , childNode )
168+ node . removeChild ( childNode ) ;
104169 return true ;
105170 } else {
106- return this . add ( xml , select , patch ) ;
171+ var node = < SVGSVGElement > select ( patch . path , xml , true ) ;
172+ if ( node ) {
173+ var parentPath = this . getParentPath ( patch . path ) ;
174+ var parentNode = < SVGSVGElement > select ( parentPath . path , xml , true ) ;
175+ if ( parentPath . isAttribute ) {
176+ parentNode . setAttribute ( parentPath . nodeName , patch . value ) ;
177+ } else {
178+ node . textContent = patch . value ;
179+ }
180+ return true ;
181+ } else {
182+ return this . add ( xml , select , patch ) ;
183+ }
107184 }
108185 }
109186
@@ -135,12 +212,12 @@ export class XmlPatcher implements patch.IPatcher {
135212 } else if ( patch . op == 'test' ) {
136213 operation = this . test . bind ( this ) ;
137214 }
138-
215+
139216 if ( ! operation ( xml , select , patch ) ) {
140217 throw new Error ( "Failed to patch xml file" ) ;
141218 }
142219 }
143-
220+
144221 return new xmldom . XMLSerializer ( ) . serializeToString ( xml ) ;
145222 }
146223}
0 commit comments