Skip to content
This repository has been archived by the owner on Aug 22, 2023. It is now read-only.

Commit

Permalink
Implemented forking, properly matching //node in inception.xml
Browse files Browse the repository at this point in the history
  • Loading branch information
StevenLooman committed Aug 19, 2012
1 parent d1ba532 commit 2d40113
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 39 deletions.
1 change: 1 addition & 0 deletions lib/child_state.js
Expand Up @@ -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 ']'
Expand Down
74 changes: 54 additions & 20 deletions lib/saxpath.js
Expand Up @@ -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;

Expand Down Expand Up @@ -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!
Expand All @@ -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);
}


Expand Down Expand Up @@ -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;
Expand All @@ -118,6 +120,7 @@ SaXPath.prototype._fork = function(state) {

// mark the forked states as forks
fork.isFork = true;
fork.enteredDepth = depth;

return fork;
};
Expand All @@ -128,20 +131,61 @@ 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
if (state.next.matches(node, this.currentDepth)) {
// do fork here?
if (state.next.doFork) {
trace(this.currentDepth, 'should fork');
forkedState = this._fork(state.next, this.currentDepth);
}

// hop to next state
Expand All @@ -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) {
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions lib/self_or_descendant_state.js
Expand Up @@ -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 ']'
Expand Down
6 changes: 4 additions & 2 deletions lib/start_state.js
Expand Up @@ -13,14 +13,16 @@ function trace(message) {
*/
function StartState() {
this.axis = '0';
this.enteredDepth = 0;
this.id = new Date().getTime() + '-' + Math.round(Math.random() * 65535);
}


/**
* 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;
Expand All @@ -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;
};


Expand Down
42 changes: 25 additions & 17 deletions test/tape_recorder.js
@@ -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 });
}
};

Expand Down

0 comments on commit 2d40113

Please sign in to comment.