@@ -78,13 +78,19 @@ function isPrefixInScope(prefixesInScope, prefix, namespaceURI)
78
78
* @return {String }
79
79
* @api private
80
80
*/
81
- ExclusiveCanonicalization . prototype . renderNs = function ( node , prefixesInScope , defaultNs , defaultNsForPrefix , inclusiveNamespacesPrefixList ) {
81
+ ExclusiveCanonicalization . prototype . renderNs = function ( node ,
82
+ prefixesInScope ,
83
+ defaultNs ,
84
+ defaultNsForPrefix ,
85
+ inclusiveNamespacesPrefixList ,
86
+ ancestorNamespaces ,
87
+ topNode
88
+ ) {
82
89
var a , i , p , attr
83
90
, res = [ ]
84
91
, newDefaultNs = defaultNs
85
92
, nsListToRender = [ ]
86
93
, currNs = node . namespaceURI || "" ;
87
-
88
94
//handle the namespaceof the node itself
89
95
if ( node . prefix ) {
90
96
if ( ! isPrefixInScope ( prefixesInScope , node . prefix , node . namespaceURI || defaultNsForPrefix [ node . prefix ] ) ) {
@@ -98,23 +104,57 @@ ExclusiveCanonicalization.prototype.renderNs = function(node, prefixesInScope, d
98
104
res . push ( ' xmlns="' , newDefaultNs , '"' ) ;
99
105
}
100
106
107
+ if ( topNode ) {
108
+ for ( var j = 0 ; j < ancestorNamespaces . length ; j ++ ) {
109
+ var ancestorNs = ancestorNamespaces [ j ] ;
110
+ for ( var k = 0 ; k < inclusiveNamespacesPrefixList . length ; k ++ ) {
111
+ var inclusiveNs = inclusiveNamespacesPrefixList [ k ] ;
112
+ if ( ancestorNs . prefix === inclusiveNs && ! isPrefixInScope ( prefixesInScope , ancestorNs . prefix , ancestorNs . namespaceURI ) ) {
113
+ nsListToRender . push ( { "prefix" : ancestorNs . prefix , "namespaceURI" : ancestorNs . namespaceURI } ) ;
114
+ prefixesInScope . push ( { "prefix" : ancestorNs . prefix , "namespaceURI" : ancestorNs . namespaceURI } ) ;
115
+ }
116
+ }
117
+ }
118
+ }
119
+
101
120
//handle the attributes namespace
102
121
if ( node . attributes ) {
103
122
for ( i = 0 ; i < node . attributes . length ; ++ i ) {
104
123
attr = node . attributes [ i ] ;
105
124
125
+
106
126
//handle all prefixed attributes that are included in the prefix list and where
107
127
//the prefix is not defined already
108
- if ( attr . prefix && ! isPrefixInScope ( prefixesInScope , attr . localName , attr . value ) && inclusiveNamespacesPrefixList . indexOf ( attr . localName ) >= 0 ) {
128
+ if ( attr . prefix &&
129
+ ! isPrefixInScope ( prefixesInScope , attr . localName , attr . value ) &&
130
+ ( inclusiveNamespacesPrefixList . indexOf ( attr . localName ) >= 0 ) ) {
109
131
nsListToRender . push ( { "prefix" : attr . localName , "namespaceURI" : attr . value } ) ;
110
132
prefixesInScope . push ( { "prefix" : attr . localName , "namespaceURI" : attr . value } ) ;
111
133
}
112
134
113
135
//handle all prefixed attributes that are not xmlns definitions and where
114
136
//the prefix is not defined already
115
- if ( attr . prefix && ! isPrefixInScope ( prefixesInScope , attr . prefix , attr . namespaceURI ) && attr . prefix != "xmlns" && attr . prefix != "xml" ) {
116
- nsListToRender . push ( { "prefix" : attr . prefix , "namespaceURI" : attr . namespaceURI } ) ;
117
- prefixesInScope . push ( { "prefix" : attr . prefix , "namespaceURI" : attr . namespaceURI } ) ;
137
+ if ( attr . prefix && attr . prefix !== "xmlns" && attr . prefix !== "xml" ) {
138
+ var artificiallyIntroduced = false ;
139
+ if ( attr . namespaceURI === undefined ) {
140
+ //This could mean that the namespace Uri has been reset to "", or it could mean we have artificially
141
+ //introduced it because it was in inclusiveNamespacePrefixList
142
+ if ( inclusiveNamespacesPrefixList . indexOf ( attr . prefix ) >= 0 ) {
143
+ for ( var j = 0 ; j < ancestorNamespaces . length ; j ++ ) {
144
+ var ancestorNs = ancestorNamespaces [ j ] ;
145
+ if ( ancestorNs . prefix === attr . prefix ) {
146
+ artificiallyIntroduced = true ;
147
+ break ;
148
+ }
149
+ }
150
+ }
151
+ }
152
+ if ( ! artificiallyIntroduced ) {
153
+ if ( ! isPrefixInScope ( prefixesInScope , attr . prefix , attr . namespaceURI ) ) {
154
+ nsListToRender . push ( { "prefix" : attr . prefix , "namespaceURI" : attr . namespaceURI || defaultNsForPrefix [ attr . prefix ] } ) ;
155
+ prefixesInScope . push ( { "prefix" : attr . prefix , "namespaceURI" : attr . namespaceURI || defaultNsForPrefix [ attr . prefix ] } ) ;
156
+ }
157
+ }
118
158
}
119
159
}
120
160
}
@@ -132,18 +172,23 @@ ExclusiveCanonicalization.prototype.renderNs = function(node, prefixesInScope, d
132
172
return { "rendered" : res . join ( "" ) , "newDefaultNs" : newDefaultNs } ;
133
173
} ;
134
174
135
- ExclusiveCanonicalization . prototype . processInner = function ( node , prefixesInScope , defaultNs , defaultNsForPrefix , inclusiveNamespacesPrefixList ) {
136
-
175
+ ExclusiveCanonicalization . prototype . processInner = function ( node ,
176
+ prefixesInScope ,
177
+ defaultNs ,
178
+ defaultNsForPrefix ,
179
+ inclusiveNamespacesPrefixList ,
180
+ ancestorNamespaces ,
181
+ topNode ) {
137
182
if ( node . nodeType === 8 ) { return this . renderComment ( node ) ; }
138
183
if ( node . data ) { return utils . encodeSpecialCharactersInText ( node . data ) ; }
139
184
140
185
var i , pfxCopy
141
- , ns = this . renderNs ( node , prefixesInScope , defaultNs , defaultNsForPrefix , inclusiveNamespacesPrefixList )
186
+ , ns = this . renderNs ( node , prefixesInScope , defaultNs , defaultNsForPrefix , inclusiveNamespacesPrefixList , ancestorNamespaces , topNode )
142
187
, res = [ "<" , node . tagName , ns . rendered , this . renderAttrs ( node , ns . newDefaultNs ) , ">" ] ;
143
188
144
189
for ( i = 0 ; i < node . childNodes . length ; ++ i ) {
145
190
pfxCopy = prefixesInScope . slice ( 0 ) ;
146
- res . push ( this . processInner ( node . childNodes [ i ] , pfxCopy , ns . newDefaultNs , defaultNsForPrefix , inclusiveNamespacesPrefixList ) ) ;
191
+ res . push ( this . processInner ( node . childNodes [ i ] , pfxCopy , ns . newDefaultNs , defaultNsForPrefix , inclusiveNamespacesPrefixList , ancestorNamespaces , false ) ) ;
147
192
}
148
193
149
194
res . push ( "</" , node . tagName , ">" ) ;
@@ -197,9 +242,10 @@ ExclusiveCanonicalization.prototype.process = function(node, options) {
197
242
var inclusiveNamespacesPrefixList = options . inclusiveNamespacesPrefixList || [ ] ;
198
243
var defaultNs = options . defaultNs || "" ;
199
244
var defaultNsForPrefix = options . defaultNsForPrefix || { } ;
245
+ var ancestorNamespaces = options . ancestorNamespaces || [ ] ;
200
246
if ( ! ( inclusiveNamespacesPrefixList instanceof Array ) ) { inclusiveNamespacesPrefixList = inclusiveNamespacesPrefixList . split ( ' ' ) ; }
201
247
202
- var res = this . processInner ( node , [ ] , defaultNs , defaultNsForPrefix , inclusiveNamespacesPrefixList ) ;
248
+ var res = this . processInner ( node , [ ] , defaultNs , defaultNsForPrefix , inclusiveNamespacesPrefixList , ancestorNamespaces , true ) ;
203
249
return res ;
204
250
} ;
205
251
0 commit comments