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