ParserCliff est une plateforme d'exécution de parsers. Elle permet l'intégration de vos propres parsers, leurs exécutions sur un texte de votre choix, et l'exportation du résultat obtenu (sous XML).
ParserCliff peut être lancé à partir d'un serveur ou localement grâce à Node WebKit
Executer
$ python -m SimpleHTTPServer 8080
ou
$ php -S localhost:8080
Pour y accéder à l'adresse : localhost:8080
ParcerCliff fonction uniquement sous Chromium/Chrome
Télécharger la dernière version de Node WebKit.
Puis suivez le «How to run apps» avec la racine du projet.
ParserCliff est une application HTML 5 propulsée par AngularJS, RequireJS et CodeMirror.
L'architecture globale de l'application tournes autour de quatre points :
- la structure de l'application est dans le fichier
index.html
, - le cœur de l'application est dans le dossier
core
, - les ressources statiques sont dans le dossier
assets
- les parsers utilisés par l'application sont dans le dossier
parsers
Chaque parsers doit :
- avoir son propre dossier dans le dossier
parsers
- avoir un fichier fichier
main.js
et un fichiermanifest.json
valide (voir ci après) - doit être présent dans la liste le fichier
preferences.json
et décrie comme actif pour fonctionner.
On prendra pour exemple le parser pAllWords, qui met tous les mots dans une balise <W></W>
.
Les manifest contiennent trois entrées :
- name : le nom du parser dans l'application. C'est le nom qui figurera dans le menu
parsers
, par exemple. - controllerName : le nom du contrôleur qui exécute le parcage. Ici c'est le nom référencé par AngularJS comme contrôleur (voir ci après).
- manifest_version : la version du manifest. La version décrite ici est la version 1.
{
"name" : "All words (\\w)",
"controllerName" : "pAllWordsCtrl",
"manifest_version" : 1
}
Le fichier main.js
permet de décrire à l'application le traitement à exécuter par le parser. Il est exécuté morceau par morceau au sein de l'application. On peut ainsi intervenir lorsque le fichier est chargé par l'application et lorsque l'on souhaite exécuter le parcage.
La première étape utilise la fonction define
de RequireJS pour définir et charger le parser.
define(function onLoad() {
// [...]
console.log("pAllWordsCtrl Loaded");
});
La seconde étape est d'enregistrer au sein de AngularJS le contrôleur qui execute le parcage. Ce contrôleur doit impérativement être lié au module 'pc' (pour Parser Ciff).
La syntaxe de définition d'un module est la syntaxe native des controller
AngularJS.
On note que le service parsingOperationSvc
est interne à ParserCliff et permet de faciliter l'exécution de parcage ligne par ligne (voir ci dessous).
angular.module('pc').controller('pAllWordsCtrl', [
'$scope', 'parsingOperationSvc', function onExecute($scope, parsingOperationSvc) {
console.log("START pAllWordsCtrl");
// [...]
}]));
Pour le parcage en lui même, on utilise la classe StringStream de CodeMirror. Celle ci permet de se balader dans le texte qu'on lui donne.
Par souci de simplicité, le service parsingOperationSvc
met à notre disposition une fonction executeParsingFct
qui prend en argument :
- le texte à parcourir,
- la fonction qui sera exécutée au cours sur parcage. Cette fonction aura dans son premier argument le flux de texte. Et peut retourner un objet dont la clé tag détermine le nom de la balise qui englobe le texte courant dans le flux.
- la fonction callback à appeler lorsque le parage est terminé. Cette fonction aura dans son premier argument le texte généré.
Ainsi, pour parser tous les mots, on définit une fonction qui prend un flux comme premièr argument et on utilise les fonctions de la classe StringStream de CodeMirror pour naviguer.
Par defaut, le texte dans l'éditeur sans balise est contenu dans la variable : $scope.inputText
. Le text visible dans l'éditeur est contenu dans la variable : $scope.parsedTextModel
.
var parseFct = function (s) {
var ch = s.next(); // On récupère le caractère suivant
if (ch =='<' && s.match(/^[^>]/)){
// On saut toutes balises
s.next();
return;
}
if (ch.match(/[^a-z\u00C0-\u017F]/i)) return; // On saut tous les caractère non alphabétique
s.match(/^[a-z\u00C0-\u017F]+/i) // On récupère tous les caractère alphabétique
return {tag: "W"}; // On les met dans une balise <W></W>
};
parsingOperationSvc.executeParsingFct($scope.parsedTextModel, parseFct,
function callback(str_o){
$scope.parsedTextModel = str_o;
// Apply change if it's not already done.
if (!$scope.$$phase) $scope.$apply();
});
define(function onLoad() {
angular.module('pc').controller('pAllWordsCtrl', [
'$scope', 'parsingOperationSvc', function onExecute($scope, parsingOperationSvc) {
console.log("START pAllWordsCtrl");
var parseFct = function (s) {
var ch = s.next();
if (ch =='<' && s.match(/^[^>]/)){
s.next();
return;
}
if (ch.match(/[^a-z\u00C0-\u017F]/i)) return;
s.match(/^[a-z\u00C0-\u017F]+/i)
return {tag: "W"};
};
parsingOperationSvc.executeParsingFct($scope.parsedTextModel, parseFct, function(str_o){
$scope.parsedTextModel = str_o;
// Apply change if it's not already done.
if (!$scope.$$phase) $scope.$apply();
});
}
]);
console.log("pAllWordsCtrl Loaded");
});