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