1 /**
  2  * @fileoverview A class which implements the xrx.xdm interface.
  3  */
  4 
  5 goog.provide('xrx.node');
  6 
  7 goog.require('xrx.xdm');
  8 
  9 
 10 
 11 /**
 12  * A class which implements the xrx.xdm interface.
 13  * 
 14  * @constructor
 15  * @implements {xrx.xdm}
 16  */
 17 xrx.node = function(pilot, type, token) {
 18   goog.base(this, pilot, xrx.node.ELEMENT, token);
 19 
 20   /**
 21    * @private
 22    */
 23   this.pilot_ = pilot;
 24 
 25   /**
 26    * @private
 27    */
 28   this.token_ = token;
 29 
 30   /**
 31    * @private
 32    */
 33   this.type_ = type;
 34 };
 35 goog.inherits(xrx.node, xrx.xdm);
 36 
 37 
 38 
 39 /** @const */ xrx.node.DOCUMENT = 0;
 40 /** @const */ xrx.node.ELEMENT = 1;
 41 /** @const */ xrx.node.ATTRIBUTE = 2;
 42 /** @const */ xrx.node.NAMESPACE = 3;
 43 /** @const */ xrx.node.PI = 4;
 44 /** @const */ xrx.node.COMMENT = 5;
 45 /** @const */ xrx.node.TEXT = 6;
 46 /** @const */ xrx.node.NODE = 7;
 47 
 48 
 49 
 50 /**
 51  * @return
 52  */
 53 xrx.node.prototype.token = function() {
 54   return this.token_;
 55 };
 56 
 57 
 58 
 59 /**
 60  * @return
 61  */
 62 xrx.node.prototype.type = function() {
 63   return this.type_;
 64 };
 65 
 66 
 67 
 68 /**
 69  * @return
 70  */
 71 xrx.node.prototype.label = function() {
 72   return this.token_.label();
 73 };
 74 
 75 
 76 
 77 /**
 78  * @return
 79  */
 80 xrx.node.prototype.offset = function() {
 81   return this.token_.offset();
 82 };
 83 
 84 
 85 
 86 /**
 87  * Returns the string-value of the required type from a node.
 88  *
 89  * @param {!xrx.node} node The node to get value from.
 90  * @return {string} The value required.
 91  */
 92 xrx.node.getValueAsString = function(node) {
 93   return node.stringValue();
 94 };
 95 
 96 
 97 
 98 /**
 99  * Returns the string-value of the required type from a node, casted to number.
100  *
101  * @param {!xrx.node} node The node to get value from.
102  * @return {number} The value required.
103  */
104 xrx.node.getValueAsNumber = function(node) {
105   return +xrx.node.getValueAsString(node);
106 };
107 
108 
109 
110 /**
111  * Returns the string-value of the required type from a node, casted to boolean.
112  *
113  * @param {!xrx.node} node The node to get value from.
114  * @return {boolean} The value required.
115  */
116 xrx.node.getValueAsBool = function(node) {
117   return !!xrx.node.getValueAsString(node);
118 };
119 
120 
121 
122 /**
123  * Returns whether two nodes are the same.
124  *
125  * @param {xrx.node} node The node to test against.
126  * @return {boolean} Whether the nodes are the same.
127  */
128 xrx.node.prototype.sameAs = function(node) {
129   return this.type() === node.type() && this.label().sameAs(
130       node.label());
131 };
132 
133 
134 
135 /**
136  * @return
137  */
138 xrx.node.prototype.isBefore = function(node) {
139   return this.type_ <= node.type() && this.label().isBefore(
140       node.label());
141 };
142 
143 
144 
145 /**
146  * @return
147  */
148 xrx.node.compareOrder = function(node1, node2) {
149   
150   if (node1.sameAs(node2)) {
151     return 0;
152   } else if (node1.isBefore(node2)) {
153     return -1;
154   } else {
155     return 1;
156   }
157 };
158 
159 
160 
161 /**
162  * @private
163  */
164 xrx.node.prototype.forward = function() {
165   var node = this;
166   var stream = node.pilot_.stream();
167   var label = node.label().clone();
168   var first = true;
169   var lastTag;
170   if (label.value(0) === 0) label.child();
171   
172   stream.rowStartTag = function(offset, length1, length2) {
173     if (first) {
174       first = false;
175     } else if (lastTag === xrx.token.START_TAG) {
176       label.child();
177     } else {
178       label.nextSibling();
179     }
180     node.nodeElement(new xrx.token.StartEmptyTag(label.clone(), offset, length1));
181 
182     if (length1 !== length2) {
183       var lbl = label.clone();
184       lbl.push0();
185       node.nodeText(new xrx.token.NotTag(lbl.clone(), 
186           offset + length1, length2 - length1));
187     }
188     lastTag = xrx.token.START_TAG;
189   };
190   
191   stream.rowEndTag = function(offset, length1, length2) {
192     if (lastTag !== xrx.token.START_TAG) label.parent();
193     if (length1 !== length2) {
194       var lbl = label.clone();
195       node.nodeText(new xrx.token.NotTag(lbl.clone(), 
196           offset + length1, length2 - length1));
197     }
198     lastTag = xrx.token.END_TAG;
199   };
200   
201   stream.rowEmptyTag = function(offset, length1, length2) {
202     if (first) {
203       first = false;
204     } else if (lastTag === xrx.token.START_TAG) {
205       label.child();
206     } else {
207       label.nextSibling();
208     }
209     node.nodeElement(new xrx.token.StartEmptyTag(label.clone(), offset, length1));
210     if (length1 !== length2) {
211       var lbl = label.clone();
212       node.nodeText(new xrx.token.NotTag(lbl.clone(), 
213           offset + length1, length2 - length1));
214     }
215     lastTag = xrx.token.END_TAG;
216   };
217   
218   stream.forward(node.offset());
219 };
220 
221 
222 
223 /**
224  * @private
225  */
226 xrx.node.prototype.backward = function() {
227   var node = this;
228   var stream = node.pilot_.stream();
229   var label = node.label().clone();
230   var lastTag = xrx.token.START_TAG;
231   
232   stream.rowStartTag = function(offset, length1, length2) {
233     if (lastTag !== xrx.token.END_TAG) label.parent();
234     node.nodeElement(new xrx.token.StartEmptyTag(label.clone(), offset, length1));
235 
236     if (length1 !== length2) {
237       var lbl = label.clone();
238       lbl.push0();
239       node.nodeText(new xrx.token.NotTag(lbl.clone(), 
240           offset + length1, length2 - length1));
241     }
242     lastTag = xrx.token.START_TAG;
243   };
244   
245   stream.rowEndTag = function(offset, length1, length2) {
246     lastTag === xrx.token.END_TAG ? label.child() : label.precedingSibling();
247     if (length1 !== length2) {
248       var lbl = label.clone();
249       node.nodeText(new xrx.token.NotTag(lbl.clone(), 
250           offset + length1, length2 - length1));
251     }
252     lastTag = xrx.token.END_TAG;
253   };
254   
255   stream.rowEmptyTag = function(offset, length1, length2) {
256     lastTag === xrx.token.END_TAG ? label.child() : label.precedingSibling();
257     node.nodeElement(new xrx.token.StartEmptyTag(label.clone(), offset, length1));
258     if (length1 !== length2) {
259       var lbl = label.clone();
260       node.nodeText(new xrx.token.NotTag(lbl.clone(), 
261           offset + length1, length2 - length1));
262     }
263     lastTag = xrx.token.START_TAG;
264   };
265   stream.backward(node.offset());
266 };
267 
268 
269 /**
270  * @private
271  */
272 xrx.node.prototype.find = function(test, axisTest, reverse) {
273   var nodeset = new xrx.xpath.NodeSet();
274   var pilot = this.pilot_;
275   var elmnt = null;
276 
277   this.nodeElement = function(token) {
278     elmnt = new xrx.node.Element(pilot, token);
279     if (axisTest.call(this.label(), token.label()) && test.matches(elmnt)) {
280       reverse ? nodeset.unshift(elmnt) : nodeset.add(elmnt);
281     }
282   };
283 
284   this.nodeText = function(token) {
285     var txt = new xrx.node.Text(pilot, token, elmnt);
286     if (axisTest.call(this.label(), token.label()) && test.matches(txt)) {
287       reverse ? nodeset.unshift(txt) : nodeset.add(txt);
288     }
289   };
290   
291   reverse ? this.backward() : this.forward();
292   return nodeset;
293 };
294 
295 
296 
297 /**
298  * @override
299  */
300 xrx.node.prototype.expandedName = function() { return ''; };
301 
302 
303 /**
304  * @override
305  */
306 xrx.node.prototype.namespaceUri = function() { return undefined; };
307 
308 
309 
310 /**
311  * @override
312  */
313 xrx.node.prototype.getAncestorNodes = function(test) {
314 
315   return this.find(test, xrx.label.prototype.isDescendantOf, true);
316 };
317 
318 
319 /**
320  * @override
321  */
322 xrx.node.prototype.getChildNodes = function(test) {
323 
324   return this.find(test, xrx.label.prototype.isParentOf);
325 };
326 
327 
328 /**
329  * Returns the descendants of a node.
330  *
331  * @private
332  * @param {!xrx.xpath.NodeTest} test A NodeTest for matching nodes.
333  * @param {!xrx.node} node The node to get descendants from.
334  * @param {?string} opt_attrName The attribute name to match, if any.
335  * @param {?string} opt_attrValue The attribute value to match, if any.
336  * @return {!xrx.xpath.NodeSet} The node-set with descendants.
337  */
338 xrx.node.prototype.getDescendantNodes = function(test) {
339 
340   return this.find(test, xrx.label.prototype.isAncestorOf);
341 };
342 
343 
344 /**
345  * @override
346  */
347 xrx.node.prototype.getFollowingSiblingNodes = function(test) {
348 
349   return this.find(test, xrx.label.prototype.isPrecedingSiblingOf);
350 };
351 
352 
353 /**
354  * @override
355  */
356 xrx.node.prototype.getFollowingNodes = function(test) {
357 
358   return this.find(test, xrx.label.prototype.isBefore);
359 };
360 
361 
362 /**
363  * @override
364  */
365 xrx.node.prototype.getAttributeNodes = function(test) {
366   var nodeset = new xrx.xpath.NodeSet();
367   var stream = this.pilot_.stream();
368   var label = this.label().clone();
369   label.child();
370   var attribute = new xrx.token.Attribute(label);
371 
372   for(;;) {
373     attribute = stream.attrName(this.token_, attribute, attribute.offset());
374     if (!attribute) break;
375     var node = new xrx.node.Attribute(this.pilot_, attribute, this)
376     if (test.matches(node)) {
377       nodeset.add(node);
378       break;
379     }
380     attribute.label().nextSibling();
381   }
382   return nodeset;
383 };
384 
385 
386 
387 /**
388  * @override
389  */
390 xrx.node.prototype.getParentNodes = function(test) {
391 
392   return this.find(test, xrx.label.prototype.isChildOf, true);
393 };
394 
395 
396 
397 /** 
398  * @constructor
399  */
400 xrx.node.Element = function(pilot, token) {
401   goog.base(this, pilot, xrx.node.ELEMENT, token);
402 };
403 goog.inherits(xrx.node.Element, xrx.node);
404 
405 
406 
407 /**
408  * @override
409  */
410 xrx.node.Element.prototype.expandedName = function() {
411   var pilot = this.pilot_;
412   return '' + pilot.xml(pilot.tagName(this.token_, this.token_));
413 };
414 
415 
416 
417 /**
418  * @override
419  */
420 xrx.node.Element.prototype.namespaceUri = function() {
421   return undefined;
422 };
423 
424 
425 /** 
426  * @constructor 
427  */
428 xrx.node.Attribute = function(pilot, token, parent) {
429   goog.base(this, pilot, xrx.node.ATTRIBUTE, token);
430   this.parent_ = parent;
431 };
432 goog.inherits(xrx.node.Attribute, xrx.node);
433 
434 
435 
436 /**
437  * @override
438  */
439 xrx.node.Attribute.prototype.getChildNodes = function() {
440   return new xrx.xpath.NodeSet();
441 };
442 
443 
444 
445 /**
446  * @override
447  */
448 xrx.node.Attribute.prototype.getDescendantNodes = function() {
449   return new xrx.xpath.NodeSet();
450 };
451 
452 
453 
454 /**
455  * @override
456  */
457 xrx.node.Attribute.prototype.getFollowingSiblingNodes = function() {
458   return new xrx.xpath.NodeSet();
459 };
460 
461 
462 
463 /**
464  * @override
465  */
466 xrx.node.Attribute.prototype.getFollowingNodes = function() {
467   return new xrx.xpath.NodeSet();
468 };
469 
470 
471 
472 /**
473  * @override
474  */
475 xrx.node.Attribute.prototype.getAttributeNodes = function() {
476   return new xrx.xpath.NodeSet();
477 };
478 
479 
480 
481 /**
482  * @override
483  */
484 xrx.node.Attribute.prototype.getParentNodes = function(test) {
485   var nodeset = new xrx.xpath.NodeSet();
486   if (test.matches(this.parent_)) nodeset.add(this.parent_); 
487 
488   return nodeset;
489 };
490 
491 
492 
493 /**
494  * @override
495  */
496 xrx.node.Attribute.prototype.expandedName = function() {
497   var stream = this.pilot_.stream();
498   var attrName = new xrx.token.AttrName(this.label().clone());
499   var token = stream.attrName(this.parent_.token(), attrName, this.offset());
500   
501   return '' + this.pilot_.xml(token);
502 };
503 
504 
505 
506 /**
507  * @override
508  */
509 xrx.node.Attribute.prototype.stringValue = function() {
510   var stream = this.pilot_.stream();
511   var attrValue = new xrx.token.AttrValue(this.label().clone());
512   var token = stream.attrValue(this.parent_.token(), attrValue, this.offset());
513   
514   return this.pilot_.xml(token);
515 };
516 
517 
518 
519 /**
520  * @override
521  */
522 xrx.node.Attribute.prototype.namespaceUri = function() {
523   return undefined;
524 };
525 
526 
527 
528 /** 
529  * @constructor 
530  */
531 xrx.node.Document = function(pilot) {
532   goog.base(this, pilot, xrx.node.DOCUMENT, new xrx.token.Root());
533 };
534 goog.inherits(xrx.node.Document, xrx.node);
535 
536 
537 
538 /** 
539  * @overwrite
540  */
541 xrx.node.Document.prototype.getAncestorNodes = function() {
542   return new xrx.xpath.NodeSet();
543 };
544 
545 
546 
547 /** 
548  * @overwrite
549  */
550 xrx.node.Document.prototype.getAttributeNodes = function() {
551   return new xrx.xpath.NodeSet();
552 };
553 
554 
555 
556 /** 
557  * @overwrite
558  */
559 xrx.node.Document.prototype.xml = function() {
560   return this.pilot_.xml();
561 };
562 
563 
564 
565 /** 
566  * @constructor 
567  */
568 xrx.node.Text = function(pilot, token, parent) {
569   goog.base(this, pilot, xrx.node.TEXT, token);
570   this.parent_ = parent;
571 };
572 goog.inherits(xrx.node.Text, xrx.node);
573 
574 
575 
576 /** 
577  * @overwrite
578  */
579 xrx.node.Text.prototype.getChildNodes = function() {
580   return new xrx.xpath.NodeSet();
581 };
582 
583 
584 
585 /** 
586  * @overwrite
587  */
588 xrx.node.Text.prototype.getDescendantNodes = function() {
589   return new xrx.xpath.NodeSet();
590 };
591 
592 
593 
594 /** 
595  * @overwrite
596  */
597 xrx.node.Text.prototype.getFollowingSiblingNodes = function(test) {
598 
599   return this.parent_.find(test, xrx.label.prototype.isPrecedingSiblingOf);
600 };
601 
602 
603 
604 /** 
605  * @overwrite
606  */
607 xrx.node.Text.prototype.getFollowingNodes = function(test) {
608 
609   return this.parent_.find(test, xrx.label.prototype.isBefore);
610 };
611 
612 
613 
614 /** 
615  * @overwrite
616  */
617 xrx.node.Text.prototype.getAttributeNodes = function() {
618   return new xrx.xpath.NodeSet();
619 };
620 
621 
622 
623 /**
624  * @override
625  */
626 xrx.node.Text.prototype.getParentNodes = function(test) {
627   var nodeset = new xrx.xpath.NodeSet();
628   if (test.matches(this.parent_)) nodeset.add(this.parent_); 
629 
630   return nodeset;
631 };
632 
633 
634 xrx.node.Text.prototype.stringValue = function() {
635   return this.pilot_.xml(this.token_);
636 };
637