Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Implemented forking, properly matching //node in inception.xml

  • Loading branch information...
commit 2d4011303fc0d62804f4925790fcceddaf5b9644 1 parent d1ba532
Steven Looman authored
1  lib/child_state.js
View
@@ -12,6 +12,7 @@ function trace(message) {
function ChildState(axis, name, predicates) {
this.axis = 'child';
this.name = name;
+ this.id = new Date().getTime() + '-' + Math.round(Math.random() * 65535);
if (predicates) {
// strip '[' and ']'
74 lib/saxpath.js
View
@@ -9,7 +9,7 @@ var ChildState = require('./child_state');
var SelfOrDescendantState = require('./self_or_descendant_state');
-var debug = true;
+var debug = false;
function trace(depth, message) {
var i;
@@ -42,7 +42,7 @@ function SaXPath(saxParser, xpath, recorder) {
this.currentDepth = 0;
this.xpathExpr = XPathParser.parse(xpath);
- this.currentState = this._parseXPathExpr(this.xpathExpr);
+ this.activeStates = [ this._parseXPathExpr(this.xpathExpr) ];
this.recorder = recorder || new XmlRecorder();
// order of binding is important here!
@@ -53,6 +53,8 @@ function SaXPath(saxParser, xpath, recorder) {
this.saxParser.on('closetag', this.onCloseTag.bind(this));
this.saxParser.on('text', this.recorder.onText.bind(this.recorder));
this.saxParser.on('end', this.onEnd.bind(this));
+
+ this.activeStates[0].matches('', 0);
}
@@ -103,7 +105,7 @@ SaXPath.prototype._parseXPathExpr = function(expr) {
};
-SaXPath.prototype._fork = function(state) {
+SaXPath.prototype._fork = function(state, depth) {
// stringify states-expression
var str = '';
var cur = state;
@@ -118,6 +120,7 @@ SaXPath.prototype._fork = function(state) {
// mark the forked states as forks
fork.isFork = true;
+ fork.enteredDepth = depth;
return fork;
};
@@ -128,13 +131,53 @@ SaXPath.prototype._fork = function(state) {
*/
SaXPath.prototype.onOpenTag = function(node) {
this.currentDepth += 1;
- trace(this.currentDepth, '=== open tag, node: ' + node.name + ' depth: ' + this.currentDepth + ' current state: ' + this.currentState.toString());
+ trace(this.currentDepth, '=== open tag, node: ' + node.name + ' depth: ' + this.currentDepth + ' current state: ' + this.activeStates[0].toString());
+
+ var newActiveStates = [];
+
+ var i;
+ for (i = 0; i < this.activeStates.length; ++i) {
+ var state = this.activeStates[i];
+ var r = this._handleOpenTag(state, node);
+ newActiveStates.push(r[0]);
+
+ if (r[1]) {
+ trace(this.currentDepth, 'add forked state');
+ newActiveStates.push(r[1]);
+ }
+ }
- this.currentState = this._handleOpenTag(this.currentState, node);
+ this.activeStates = newActiveStates;
+};
+
+/**
+ * Test if the current state unmatches this node
+ */
+SaXPath.prototype.onCloseTag = function(tag) {
+ trace(this.currentDepth, '=== close tag, node: ' + tag + ' depth: ' + this.currentDepth + ' current state: ' + this.activeStates[0].toString());
+
+ var newActiveStates = [];
+
+ var i;
+ for (i = 0; i < this.activeStates.length; ++i) {
+ var state = this.activeStates[i];
+ var r = this._handleCloseTag(state, tag);
+
+ if (r) {
+ newActiveStates.push(r);
+ } else {
+ trace(this.currentDepth, 'remove forked state');
+ }
+ }
+
+ this.activeStates = newActiveStates;
+
+ this.currentDepth -= 1;
};
SaXPath.prototype._handleOpenTag = function(state, node) {
var newState = state;
+ var forkedState = null;
if (state.next) {
// still matching states
@@ -142,6 +185,7 @@ SaXPath.prototype._handleOpenTag = function(state, node) {
// do fork here?
if (state.next.doFork) {
trace(this.currentDepth, 'should fork');
+ forkedState = this._fork(state.next, this.currentDepth);
}
// hop to next state
@@ -156,18 +200,7 @@ SaXPath.prototype._handleOpenTag = function(state, node) {
}
}
- return newState;
-};
-
-/**
- * Test if the current state unmatches this node
- */
-SaXPath.prototype.onCloseTag = function(tag) {
- trace(this.currentDepth, '=== close tag, node: ' + tag + ' depth: ' + this.currentDepth + ' current state: ' + this.currentState.toString());
-
- this.currentState = this._handleCloseTag(this.currentState, tag);
-
- this.currentDepth -= 1;
+ return [ newState, forkedState ];
};
SaXPath.prototype._handleCloseTag = function(state, tag) {
@@ -186,10 +219,11 @@ SaXPath.prototype._handleCloseTag = function(state, tag) {
// forked here? then remove this state-stack
if (state.isFork) {
trace(this.currentDepth, 'should unfork');
+ newState = null;
+ } else {
+ // hop to previous state
+ newState = state.previous;
}
-
- // hop to previous state
- newState = state.previous;
}
return newState;
1  lib/self_or_descendant_state.js
View
@@ -13,6 +13,7 @@ function SelfOrDescendantState(axis, name, predicates) {
this.doFork = true;
this.axis = 'self-or-descendant';
this.name = name;
+ this.id = new Date().getTime() + '-' + Math.round(Math.random() * 65535);
if (predicates) {
// strip '[' and ']'
6 lib/start_state.js
View
@@ -13,7 +13,7 @@ function trace(message) {
*/
function StartState() {
this.axis = '0';
- this.enteredDepth = 0;
+ this.id = new Date().getTime() + '-' + Math.round(Math.random() * 65535);
}
@@ -21,6 +21,8 @@ function StartState() {
* Match this node? (always true)
*/
StartState.prototype.matches = function(node, depth) {
+ this.enteredDepth = depth;
+
trace('0 match? node: ' + node.name + ' depth: ' + depth);
trace('0 match');
return true;
@@ -31,7 +33,7 @@ StartState.prototype.matches = function(node, depth) {
*/
StartState.prototype.unmatches = function(tag, depth) {
trace('0 unmatch? depth: ' + depth + ' enteredDepth: ' + this.enteredDepth);
- return false;
+ return this.enteredDepth >= depth;
};
42 test/tape_recorder.js
View
@@ -1,45 +1,53 @@
function TapeRecorder() {
this.box = [];
- this.tape = null;
-
- this.tapeOn = false;
+ this.deck = {};
}
TapeRecorder.prototype.start = function(state) {
- if (this.tapeOn) {
+ if (this.deck[state.id]) {
throw new Error("Tape is already on");
}
- this.tapeOn = true;
+ var tape = [];
+ tape.push({ start: true });
- this.tape = [];
- this.tape.push({ start: true });
+ this.deck[state.id] = tape;
};
TapeRecorder.prototype.stop = function(state) {
- this.tapeOn = false;
+ var tape = this.deck[state.id];
+
+ tape.push({ stop: true });
+ this.box.push(tape);
- this.tape.push({ stop: true });
- this.box.push(this.tape);
- this.tape = null;
+ delete this.deck[state.id];
};
TapeRecorder.prototype.onOpenTag = function(node) {
- if (this.tapeOn) {
- this.tape.push({ openTag: node });
+ var tape;
+ var id;
+ for (id in this.deck) {
+ tape = this.deck[id];
+ tape.push({ openTag: node });
}
};
TapeRecorder.prototype.onCloseTag = function(tag) {
- if (this.tapeOn) {
- this.tape.push({ closeTag: tag });
+ var tape;
+ var id;
+ for (id in this.deck) {
+ tape = this.deck[id];
+ tape.push({ closeTag: tag });
}
};
TapeRecorder.prototype.onText = function (text) {
- if (this.tapeOn) {
- this.tape.push({ text: text });
+ var tape;
+ var id;
+ for (id in this.deck) {
+ tape = this.deck[id];
+ tape.push({ text: text });
}
};
Please sign in to comment.
Something went wrong with that request. Please try again.