marko/lib/compiler/ParseTreeBuilder.js
2014-01-07 16:59:30 -07:00

165 lines
6.7 KiB
JavaScript

/*
* Copyright 2011 eBay Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
define.Class(
'raptor/templating/compiler/ParseTreeBuilder',
['raptor'],
function(raptor, require, exports, module) {
"use strict";
var logger = module.logger(),
sax = require('raptor/xml/sax'),
forEach = raptor.forEach,
TextNode = require('raptor/templating/compiler/TextNode'),
ElementNode = require('raptor/templating/compiler/ElementNode');
var ParseTreeBuilder = function() {
};
ParseTreeBuilder.parse = function(src, filePath, taglibs) {
var builder = new ParseTreeBuilder();
return builder.parse(src, filePath, taglibs);
};
ParseTreeBuilder.prototype = {
/**
* @param src {String} The XML source code to parse
* @param src {String} The file path (for debugging and error reporting purposes)
* @param taglibs {raptor/templating/compiler/TaglibCollection} The taglib collection. Required for resolving taglib URIs when short names are used.
*/
parse: function(src, filePath, taglibs) {
var logger = logger,
parentNode = null,
rootNode = null,
prevTextNode = null,
imports,
parser = sax.createParser({
trim: false,
normalize: false,
dom: src.documentElement != null
}),
characters = function(t, isCDATA) {
if (!parentNode) {
return; //Some bad XML parsers allow text after the ending element...
}
if (prevTextNode) {
prevTextNode.text += t;
}
else {
prevTextNode = new TextNode(t);
prevTextNode.pos = parser.getPos();
parentNode.appendChild(prevTextNode);
}
};
parser.on({
error: function(e) {
throw raptor.createError(e);
},
characters: function(t) {
characters(t, false);
},
cdata: function(t) {
characters(t, true);
},
startElement: function(el) {
prevTextNode = null;
var importsAttr,
importedAttr,
importedTag;
var elementNode = new ElementNode(
el.getLocalName(),
taglibs.resolveURI(el.getNamespaceURI()),
el.getPrefix());
elementNode.addNamespaceMappings(el.getNamespaceMappings());
elementNode.pos = parser.getPos();
forEach(el.getAttributes(), function(attr) {
if (attr.getLocalName() === 'imports' && !attr.getNamespaceURI()) {
importsAttr = attr.getValue();
}
}, this);
if (parentNode) {
parentNode.appendChild(elementNode);
}
else {
rootNode = elementNode;
if (importsAttr) {
imports = taglibs.getImports(importsAttr);
}
}
forEach(el.getAttributes(), function(attr) {
var attrURI = taglibs.resolveURI(attr.getNamespaceURI()),
attrLocalName = attr.getLocalName(),
attrPrefix = attr.getPrefix();
if (!attrURI && imports && (importedAttr = imports.getImportedAttribute(attrLocalName))) {
attrURI = importedAttr.uri;
attrLocalName = importedAttr.name;
attrPrefix = importedAttr.prefix;
}
elementNode.setAttributeNS(
attrURI,
attrLocalName,
attr.getValue(),
attrPrefix);
}, this);
if (!elementNode.uri && imports && (importedTag = imports.getImportedTag(elementNode.localName))) {
elementNode.uri = importedTag.uri;
elementNode.localName = importedTag.name;
elementNode.prefix = importedTag.prefix;
}
parentNode = elementNode;
},
endElement: function () {
prevTextNode = null;
parentNode = parentNode.parentNode;
}
}, this);
parser.parse(src, filePath);
rootNode.setRoot(true);
return rootNode;
},
getRootNode: function() {
return this.rootNode;
}
};
return ParseTreeBuilder;
});