@@ -11,6 +11,7 @@ import {
1111} from '../constants' ;
1212import { domGetAttributeValue } from './functions' ;
1313import { XNode } from './xnode' ;
14+ import { XDocument } from './xdocument' ;
1415
1516// Returns the text value of a node; for nodes without children this
1617// is the nodeValue, for nodes with children this is the concatenation
@@ -21,6 +22,48 @@ export function xmlValue(node: any, disallowBrowserSpecificOptimization: boolean
2122 return '' ;
2223 }
2324
25+ let ret = '' ;
26+ if ( node . nodeType == DOM_TEXT_NODE || node . nodeType == DOM_CDATA_SECTION_NODE ) {
27+ ret += node . nodeValue ;
28+ } else if ( node . nodeType == DOM_ATTRIBUTE_NODE ) {
29+ ret += node . nodeValue ;
30+ } else if (
31+ node . nodeType == DOM_ELEMENT_NODE ||
32+ node . nodeType == DOM_DOCUMENT_NODE ||
33+ node . nodeType == DOM_DOCUMENT_FRAGMENT_NODE
34+ ) {
35+ if ( ! disallowBrowserSpecificOptimization ) {
36+ // IE, Safari, Opera, and friends
37+ const innerText = node . innerText ;
38+ if ( innerText != undefined ) {
39+ return innerText ;
40+ }
41+ // Firefox
42+ const textContent = node . textContent ;
43+ if ( textContent != undefined ) {
44+ return textContent ;
45+ }
46+ }
47+
48+ if ( node . transformedChildNodes . length > 0 ) {
49+ for ( let i = 0 ; i < node . transformedChildNodes . length ; ++ i ) {
50+ ret += xmlValue ( node . transformedChildNodes [ i ] ) ;
51+ }
52+ } else {
53+ for ( let i = 0 ; i < node . childNodes . length ; ++ i ) {
54+ ret += xmlValue ( node . childNodes [ i ] ) ;
55+ }
56+ }
57+ }
58+ return ret ;
59+ }
60+
61+ // TODO: Give a better name to this.
62+ export function xmlValue2 ( node : any , disallowBrowserSpecificOptimization : boolean = false ) {
63+ if ( ! node ) {
64+ return '' ;
65+ }
66+
2467 let ret = '' ;
2568 if ( node . nodeType == DOM_TEXT_NODE || node . nodeType == DOM_CDATA_SECTION_NODE ) {
2669 ret += node . nodeValue ;
@@ -44,22 +87,27 @@ export function xmlValue(node: any, disallowBrowserSpecificOptimization: boolean
4487 }
4588 }
4689 // pobrecito!
47- const len = node . childNodes . length ;
90+ const len = node . transformedChildNodes . length ;
4891 for ( let i = 0 ; i < len ; ++ i ) {
49- ret += xmlValue ( node . childNodes [ i ] ) ;
92+ ret += xmlValue ( node . transformedChildNodes [ i ] ) ;
5093 }
5194 }
5295 return ret ;
5396}
5497
55- // Returns the representation of a node as XML text.
56- export function xmlText ( node : any , opt_cdata : boolean = false ) {
98+ /**
99+ * Returns the representation of a node as XML text.
100+ * @param node The starting node.
101+ * @param opt_cdata If using CDATA configuration.
102+ * @returns The XML string.
103+ */
104+ export function xmlText ( node : XNode , opt_cdata : boolean = false ) {
57105 const buf = [ ] ;
58106 xmlTextRecursive ( node , buf , opt_cdata ) ;
59107 return buf . join ( '' ) ;
60108}
61109
62- function xmlTextRecursive ( node : any , buf : any [ ] , cdata : any ) {
110+ function xmlTextRecursive ( node : XNode , buf : any [ ] , cdata : any ) {
63111 if ( node . nodeType == DOM_TEXT_NODE ) {
64112 buf . push ( xmlEscapeText ( node . nodeValue ) ) ;
65113 } else if ( node . nodeType == DOM_CDATA_SECTION_NODE ) {
@@ -95,12 +143,111 @@ function xmlTextRecursive(node: any, buf: any[], cdata: any) {
95143 }
96144}
97145
98- function xmlFullNodeName ( n : any ) {
99- if ( n . prefix && n . nodeName . indexOf ( `${ n . prefix } :` ) != 0 ) {
100- return `${ n . prefix } :${ n . nodeName } ` ;
146+ /**
147+ * Returns the representation of a node as XML text.
148+ * @param node The starting node.
149+ * @param opt_cdata If using CDATA configuration.
150+ * @returns The XML string.
151+ */
152+ export function xmlTransformedText ( node : XNode , opt_cdata : boolean = false ) {
153+ const buffer = [ ] ;
154+ xmlTransformedTextRecursive ( node , buffer , opt_cdata ) ;
155+ return buffer . join ( '' ) ;
156+ }
157+
158+ function xmlTransformedTextRecursive ( node : XNode , buffer : any [ ] , cdata : boolean ) {
159+ if ( node . printed ) return ;
160+ const nodeType = node . transformedNodeType || node . nodeType ;
161+ const nodeValue = node . transformedNodeValue || node . nodeValue ;
162+ if ( nodeType == DOM_TEXT_NODE ) {
163+ if ( node . transformedNodeValue && node . transformedNodeValue . trim ( ) !== '' ) {
164+ buffer . push ( xmlEscapeText ( node . transformedNodeValue ) ) ;
165+ }
166+ } else if ( nodeType == DOM_CDATA_SECTION_NODE ) {
167+ if ( cdata ) {
168+ buffer . push ( nodeValue ) ;
169+ } else {
170+ buffer . push ( `<![CDATA[${ nodeValue } ]]>` ) ;
171+ }
172+ } else if ( nodeType == DOM_COMMENT_NODE ) {
173+ buffer . push ( `<!--${ nodeValue } -->` ) ;
174+ } else if ( nodeType == DOM_ELEMENT_NODE ) {
175+ // If node didn't have a transformed name, but its children
176+ // had transformations, children should be present at output.
177+ // This is called here "muted logic".
178+ if ( node . transformedNodeName !== null && node . transformedNodeName !== undefined ) {
179+ xmlElementLogicTrivial ( node , buffer , cdata ) ;
180+ } else {
181+ xmlElementLogicMuted ( node , buffer , cdata ) ;
182+ }
183+ } else if ( nodeType == DOM_DOCUMENT_NODE || nodeType == DOM_DOCUMENT_FRAGMENT_NODE ) {
184+ const childNodes = node . transformedChildNodes . concat ( node . childNodes ) ;
185+ // const childNodes = node.transformedChildNodes.length > 0 ? node.transformedChildNodes : node.childNodes;
186+ for ( let i = 0 ; i < childNodes . length ; ++ i ) {
187+ xmlTransformedTextRecursive ( childNodes [ i ] , buffer , cdata ) ;
188+ }
189+ }
190+
191+ node . printed = true ;
192+ }
193+
194+ /**
195+ * XML element output, trivial logic.
196+ * @param node The XML node.
197+ * @param buffer The XML buffer.
198+ * @param cdata If using CDATA configuration.
199+ */
200+ function xmlElementLogicTrivial ( node : XNode , buffer : any [ ] , cdata : boolean ) {
201+ buffer . push ( `<${ xmlFullNodeName ( node ) } ` ) ;
202+
203+ const attributes = node . transformedAttributes || node . attributes ;
204+ for ( let i = 0 ; i < attributes . length ; ++ i ) {
205+ const attribute = attributes [ i ] ;
206+ if ( ! attribute ) {
207+ continue ;
208+ }
209+
210+ const attributeNodeName = attribute . transformedNodeName || attribute . nodeName ;
211+ const attributeNodeValue = attribute . transformedNodeValue || attribute . nodeValue ;
212+ if ( attributeNodeName && attributeNodeValue ) {
213+ buffer . push ( ` ${ xmlFullNodeName ( attribute ) } ="${ xmlEscapeAttr ( attributeNodeValue ) } "` ) ;
214+ }
215+ }
216+
217+ const childNodes = node . transformedChildNodes . length > 0 ? node . transformedChildNodes : node . childNodes ;
218+ if ( childNodes . length == 0 ) {
219+ buffer . push ( '/>' ) ;
220+ } else {
221+ buffer . push ( '>' ) ;
222+ for ( let i = 0 ; i < childNodes . length ; ++ i ) {
223+ xmlTransformedTextRecursive ( childNodes [ i ] , buffer , cdata ) ;
224+ }
225+ buffer . push ( `</${ xmlFullNodeName ( node ) } >` ) ;
226+ }
227+ }
228+
229+ /**
230+ * XML element output, muted logic.
231+ * In other words, this element should not be printed, but its
232+ * children can be printed if they have transformed values.
233+ * @param node The XML node.
234+ * @param buffer The XML buffer.
235+ * @param cdata If using CDATA configuration.
236+ */
237+ function xmlElementLogicMuted ( node : XNode , buffer : any [ ] , cdata : boolean ) {
238+ const childNodes = node . transformedChildNodes . length > 0 ? node . transformedChildNodes : node . childNodes ;
239+ for ( let i = 0 ; i < childNodes . length ; ++ i ) {
240+ xmlTransformedTextRecursive ( childNodes [ i ] , buffer , cdata ) ;
101241 }
242+ }
102243
103- return n . nodeName ;
244+ function xmlFullNodeName ( node : XNode ) {
245+ const nodeName = node . transformedNodeName || node . nodeName ;
246+ if ( node . transformedPrefix && nodeName . indexOf ( `${ node . transformedPrefix } :` ) != 0 ) {
247+ return `${ node . transformedPrefix } :${ nodeName } ` ;
248+ }
249+
250+ return nodeName ;
104251}
105252
106253/**
@@ -157,13 +304,17 @@ export function xmlGetAttribute(node: XNode, name: string) {
157304 * and other nodes: for the document node, the owner document is the
158305 * node itself, for all others it's the ownerDocument property.
159306 *
160- * @param {Node } node
161- * @return {Document }
307+ * @param {XNode } node
308+ * @return {XDocument }
162309 */
163- export function xmlOwnerDocument ( node : any ) {
164- if ( node . nodeType == DOM_DOCUMENT_NODE ) {
165- return node ;
310+ export function xmlOwnerDocument ( node : XNode ) : XDocument {
311+ if ( node === null || node === undefined ) {
312+ throw new Error ( 'Node has no valid owner document.' ) ;
313+ }
314+
315+ if ( node . nodeType === DOM_DOCUMENT_NODE ) {
316+ return node as XDocument ;
166317 }
167318
168- return node . ownerDocument ;
319+ return xmlOwnerDocument ( node . ownerDocument ) ;
169320}
0 commit comments