Shenma est-elle un "mode interprète"?
Ouvrez d'abord le «GoF» et jetons un coup d'œil à la définition:
Compte tenu d'une langue, définissez une représentation de sa grammaire et définissez un interprète qui utilise cette représentation pour interpréter les phrases dans la langue.
Avant le début, j'ai encore besoin de populariser plusieurs concepts:
Syntaxe abstrait:
Le modèle d'interprète n'explique pas comment créer un arbre de syntaxe abstrait. Il n'implique pas d'analyse grammaticale. Une arborescence de syntaxe abstraite peut être complétée par un programme d'analyse de syntaxe basée sur une table, ou créée par programme d'analyse de syntaxe manuscrite (généralement récursive), ou fourni directement par le client.
Analyseur:
Il fait référence à un programme qui décrit les expressions requises par l'appel client et forme un arbre de syntaxe abstrait après l'analyse.
Interprète:
Fait référence à un programme qui explique l'arborescence de syntaxe abstraite et exécute les fonctions correspondantes de chaque nœud.
Une condition préalable importante pour utiliser le modèle d'interprète consiste à définir un ensemble de règles grammaticales, également connues sous le nom de grammaire. Que les règles de cette grammaire soient simples ou complexes, ces règles doivent être incluses, car le mode interprète est d'analyser et d'exécuter des fonctions correspondantes en conséquence.
Jetons un coup d'œil au schéma de structure et à la description du mode interprète:
AbstractExpression: définit l'interface de l'interprète et accepte l'opération d'interprétation de l'interprète.
Terminalexpression: terminalexpression, utilisé pour mettre en œuvre des opérations liées à Terminator dans les règles de syntaxe, ne contient plus d'autres interprètes. Si le motif de combinaison est utilisé pour construire un arbre de syntaxe abstrait, il équivaut à un objet de feuille dans le motif de combinaison, et il peut y avoir plusieurs interprètes de terminateur.
Non terminalexpression: un interprète non terminal, utilisé pour mettre en œuvre des opérations non liées aux terminaux dans les règles de syntaxe. Habituellement, un interprète correspond à une règle de syntaxe et peut contenir d'autres interprètes. Si le modèle de composition est utilisé pour construire un arbre de syntaxe abstrait, il équivaut à un objet combiné dans le motif de composition. Il peut y avoir plusieurs interprètes non terminaux.
Contexte: Contexte, contient généralement des données requises par chaque interprète ou fonctions publiques.
Client: Un client fait référence à un client qui utilise un interprète. Habituellement, les expressions effectuées en fonction de la syntaxe du langage sont converties en une syntaxe abstraite décrite par l'objet interprète, puis une opération d'explication est appelée.
Ici, nous utilisons un exemple XML pour comprendre le modèle d'interprète:
Tout d'abord, nous devons concevoir une grammaire simple pour l'expression. À des fins générales, utilisez la racine pour représenter l'élément racine, ABC, etc. pour représenter l'élément. Un XML simple est le suivant:
La copie de code est la suivante:
<? xml version = "1.0" coding = "utf-8">
<root id = "rootId">
<a>
<b>
<c name = "testc"> 12345 </c>
<d id = "1"> d1 </d>
<d id = "2"> d2 </d>
<d id = "3"> d3 </d>
<d id = "4"> d4 </d>
</b>
</a>
</ root>
La grammaire de l'expression de la convention est la suivante:
1. Obtenez la valeur d'un seul élément: commencez à partir de l'élément racine et jusqu'à l'élément dont vous souhaitez obtenir la valeur. Le milieu de l'élément est séparé par "/" et no "/" est ajouté avant l'élément racine. Par exemple, l'expression "root / a / b / c" signifie obtenir les valeurs de l'élément C sous l'élément racine, l'élément A, l'élément B et l'élément c.
2. Obtenez la valeur de l'attribut d'un seul élément: bien sûr, il existe plusieurs attributs. L'attribut pour obtenir la valeur doit être l'attribut du dernier élément de l'expression. Ajouter "." Après le dernier élément, puis ajoutez le nom de l'attribut. Par exemple, l'expression "root / a / b / c.name" signifie obtenir la valeur de l'attribut de nom de l'élément racine, élément A, élément b, élément c.
3. Obtenez la valeur du même nom d'élément, bien sûr, il y a plusieurs éléments. L'élément pour obtenir la valeur doit être le dernier élément de l'expression et ajouter "$" après le dernier élément. Par exemple, l'expression "root / a / b / d $" représente la collection de valeurs de plusieurs éléments D sous l'élément racine, sous l'élément A et sous l'élément B.
4. Obtenez la valeur de l'attribut avec le même nom d'élément, bien sûr, il y a plusieurs: l'élément pour obtenir la valeur d'attribut doit être le dernier élément de l'expression et ajouter "$" après le dernier élément. Par exemple, l'expression "root / a / b / d $ .id $" représente la collection de valeurs de plusieurs attributs d'ID d'éléments d sous l'élément racine, sous l'élément A, et sous l'élément B.
Le XML ci-dessus, correspondant à l'arbre de syntaxe abstrait, et la structure possible est illustrée à la figure:
Jetons un coup d'œil au code spécifique ci-dessous:
1. Définir le contexte:
La copie de code est la suivante:
/ **
* Contexte, utilisé pour contenir certaines informations globales requises par l'interprète
* @param {string} filepathName [chemin et nom du xml qui doit être lu]
* /
Contexte de fonction (filepathName) {
// l'élément traité précédent
this.preele = null;
// Objet de document XML
this.Document = xmLutil.getRoot (filePathName);
}
Context.prototype = {
// réinitialiser le contexte
reinit: function () {
this.preele = null;
},
/ **
* Méthodes d'utilisation du public de chaque expression
* Obtenez l'élément actuel en fonction du nom de l'élément parent et de l'élément actuel
* @param {élément} pele [élément parent]
* @param {String} eLename [Nom de l'élément actuel]
* @return {élément | null} [élément actuel trouvé]
* /
getNowele: fonction (pele, elename) {
var tempNodelist = pele.childnodes;
var nowele;
for (var i = 0, len = tempNodeList.length; i <len; i ++) {
if ((nowele = tempNodelist [i]). nodetype === 1)
if (nowele.nodename === elename)
retourne nowele;
}
retourner null;
},
getPreele: function () {
Renvoyez ce.preele;
},
setPreele: fonction (preele) {
this.preele = preele;
},
getDocument: function () {
Renvoyez ce.Document;
}
};
Dans le contexte, j'ai utilisé un objet Tool Xmlutil pour obtenir XMLDOM. Ci-dessous, j'utilise Dompaser de Dom3. Certains navigateurs peuvent ne pas le soutenir. Veuillez utiliser le navigateur de base:
La copie de code est la suivante:
// objet d'outil
// analyse XML pour obtenir l'objet de document correspondant
var xmlutil = {
getroot: function (filepathname) {
var parser = new DOMPARSER ();
var xmldom = parser.parsefromString ('<root id = "rootId"> <a> <b> <c name = "testc"> 12345 </c> <d id = "1"> d1 </ d> <d id = "2"> d2 </d> <d id = "3"> d3 </d> </ D3 id = "4"> d4 </d> </b> </a> </ root> ',' text / xml ');
retour xmldom;
}
};
Voici le code de l'interprète:
La copie de code est la suivante:
/ **
* Les éléments sont utilisés comme interprètes correspondant à des non-terminaux pour interpréter et exécuter des éléments intermédiaires
* @param {String} eLename [Nom de l'élément]
* /
fonction ElementExpression (eLename) {
this.eles = [];
this.elename = eLename;
}
ElementExpression.prototype = {
adddele: fonction (eLename) {
this.eles.push (elename);
Retour Vrai;
},
RETI-REVEPELLE: fonction (ele) {
pour (var i = 0, len = this.eles.length; i <len; i ++) {
if (ele === this.eles [i])
this.eles.splice (i--, 1);
}
Retour Vrai;
},
Interpréter: fonction (contexte) {
// supprime d'abord l'élément actuel dans le contexte en tant qu'élément parent
// Trouvez l'élément XML correspondant au nom de l'élément actuel et remettez-le sur le contexte
var pele = context.getPreele ();
if (! pele) {
// indique que l'élément racine est maintenant obtenu
context.setPreele (context.getDocument (). documentElement);
} autre {
// Obtenez l'élément actuel en fonction du nom de l'élément parent et de l'élément à rechercher
var nowele = context.getNowele (pele, this.elename);
// Mettez l'élément actuellement récupéré dans le contexte
context.setpreele (nowele);
}
var ss;
// boucle pour appeler la méthode d'interprétation de l'élément enfant
pour (var i = 0, len = this.eles.length; i <len; i ++) {
ss = this.eles [i] .interpret (context);
}
// Renvoie le résultat de l'explication du dernier interprète. Généralement, le dernier interprète est l'interprète Terminator.
retour ss;
}
};
/ **
* Les éléments sont utilisés comme interprète correspondant au terminateur
* @param {String} Nom [Nom de l'élément]
* /
fonction elementTerminalexpression (name) {
this.elename = name;
}
Elementterminalexpression.prototype = {
Interpréter: fonction (contexte) {
var pele = context.getPreele ();
var ele = null;
if (! pele) {
ele = context.getDocument (). documentElement;
} autre {
ele = context.getNowele (pele, this.elename);
context.setpreele (ele);
}
// Obtenez la valeur de l'élément
retour ele.firstchild.nodevalue;
}
};
/ **
* L'attribut est utilisé comme interprète correspondant au terminateur
* @param {string} propname [nom de l'attribut]
* /
fonction Propertyterminalexpression (propName) {
this.propName = propName;
}
Propriététerminalexpression.prototype = {
Interpréter: fonction (contexte) {
// Obtenez directement la valeur de l'attribut d'élément dernier
return context.getPreele (). getAttribute (this.propName);
}
};
Voyons d'abord comment utiliser l'interprète pour obtenir la valeur d'un seul élément:
La copie de code est la suivante:
void function () {
var c = nouveau contexte ();
// souhaite obtenir la valeur de plusieurs éléments D, c'est-à-dire la valeur de l'expression suivante: "Root / A / B / C"
// Tout d'abord, vous devez construire un arbre syntaxe abstrait pour l'interprète
var root = new ElementExpression ('root');
var aele = new ElementExpression ('a');
var bele = new ElementExpression ('b');
var cele = new ElementTerMinalexpression ('C');
// Combinaison
root.addele (aele);
aele.addele (Bele);
Bele.Addele (Cele);
Console.log ('C de la valeur est =' + root.interpret (c));
} ();
Sortie: La valeur de C est = 12345
Ensuite, nous utilisons le code ci-dessus pour obtenir la valeur de l'attribut d'un seul élément:
La copie de code est la suivante:
void function () {
var c = nouveau contexte ();
// Je veux obtenir l'attribut ID de l'élément D, c'est-à-dire la valeur de l'expression suivante: "A / b / c.Name"
// Cette fois, C n'est pas terminé, et vous devez modifier C vers ElementExpression
var root = new ElementExpression ('root');
var aele = new ElementExpression ('a');
var bele = new ElementExpression ('b');
var cele = new ElementExpression ('c');
var prop = new PropertyTerMinalexpression ('name');
// Combinaison
root.addele (aele);
aele.addele (Bele);
Bele.Addele (Cele);
Cele.addele (PROP);
Console.log ('C's Nom de la propriété La valeur est =' + root.interpret (c));
// Si vous souhaitez utiliser le même contexte et analyser en continu, vous devez réinitialiser l'objet de contexte
// Par exemple, vous devez recueilli la valeur du nom d'attribut à nouveau successivement, bien sûr, vous pouvez recombiner les éléments
// Regarse, tant que le même contexte est utilisé, l'objet de contexte doit être réinitialisé
C.Reinit ();
Console.log ('La valeur du nom de la propriété de RegEt C est =' + root.interpret (c));
} ();
Sortie: La valeur du nom d'attribut de C est = TestC Récupérer la valeur du nom d'attribut de C est = TestC
expliquer:
1. Fonction du mode interprète:
Le modèle d'interprète utilise des objets interprètes pour représenter et traiter les règles de syntaxe correspondantes. Généralement, un interprète gère une règle de syntaxe. Théoriquement, tant que les expressions conformes à la syntaxe peuvent être représentées par l'objet interprète et peuvent former une arborescence de syntaxe abstraite, le motif d'interprète peut être utilisé pour le gérer.
2. Règles et interprètes de syntaxe
Il existe une correspondance entre les règles de syntaxe et les interprètes. Généralement, un interprète gère une règle de syntaxe, mais l'inverse n'est pas vrai. Une règle de syntaxe peut avoir plusieurs interprétations et traitement, c'est-à-dire qu'une règle de syntaxe peut correspondre à plusieurs interprètes.
3. Contexte Community
Le contexte joue un rôle très important en mode interprète. Parce que le contexte est transmis à tous les interprètes. Par conséquent, l'état de l'interprète peut être stocké et accessible dans le contexte. Par exemple, l'interprète précédent peut stocker certaines données dans le contexte, et le dernier interprète peut obtenir ces valeurs.
De plus, certaines données en dehors de l'interprète peuvent être transmises dans le contexte, mais l'interprète en a besoin et certaines données publiques globales.
Il existe également une fonction dans le contexte, à savoir qu'elle peut fournir les fonctions communes de tous les objets d'interprète, similaires aux combinaisons d'objets, plutôt que d'utiliser l'héritage pour obtenir des fonctions communes, qui peuvent être appelées dans chaque objet interprète.
4. Qui construira une syntaxe abstraite
Dans l'exemple précédent, il est très difficile de construire manuellement l'arborescence de syntaxe abstraite du côté client, mais en mode interprète, cette partie de la fonction n'est pas impliquée, et il n'est responsable que de l'interprétation et du traitement de l'arborescence de syntaxe abstraite construite. Nous présenterons que nous pouvons fournir un analyseur pour convertir les expressions en arbres de syntaxe abstraits.
Il y a un autre problème, c'est-à-dire qu'une règle de syntaxe peut correspondre à plusieurs objets d'interprète, c'est-à-dire que le même élément peut être converti en plusieurs objets d'interprète, ce qui signifie que la même expression peut former un arbre de syntaxe abstrait inutile, ce qui rend également difficile de construire un arbre de syntaxe abstrait et la charge de travail est très grande.
5. qui est responsable de l'explication de l'opération
Tant que l'arbre de syntaxe abstrait est défini, l'interprète doit être responsable de l'interprétation et de l'exécution. Bien qu'il existe différentes règles de syntaxe, l'interprète n'est pas responsable du choix de l'objet interprète à utiliser pour interpréter les règles de syntaxe d'exécution. La fonction de sélection de l'interprète est terminée lors de la construction d'un arbre de syntaxe abstrait.
6. L'ordre d'appel du mode interprète
1) Créer un objet de contexte
2) Créez plusieurs objets interprètes et combinez des arbres de syntaxe abstraits
3) Invoquez l'opération d'interprétation de l'objet interprète
3.1) Stocker et accéder à l'état de l'interprète à travers le contexte.
Pour les objets d'interprète non terminateur, appelez récursivement l'objet sous-inter-inter-interordant qu'il contient.
L'essence du modèle d'interprète: * Implémentation séparée, interpréter l'exécution *
Le module interprète utilise un objet interprète pour traiter une règle de syntaxe pour séparer les fonctions complexes; Sélectionne ensuite les fonctions qui doivent être exécutées et combine ces fonctions dans une arborescence de syntaxe abstraite qui doit être interprétée et exécutée; Interprète ensuite l'exécution en fonction de l'arborescence de syntaxe abstraite pour implémenter les fonctions correspondantes.
En surface, le mode interprète se concentre sur le traitement de la syntaxe personnalisée que nous n'utilisons généralement pas; Mais en substance, l'idée du mode interprète est alors la séparation, l'encapsulation, la simplification et est la même que de nombreux modes.
Par exemple, le mode interprète peut être utilisé pour simuler la fonction du mode d'état. Si la syntaxe à traiter par le mode interprète est simplifiée à une seule marque d'état, l'interprète est considéré comme un objet de traitement pour l'état. Pour la même syntaxe représentant l'état, il peut y avoir de nombreux interprètes inutilisés, c'est-à-dire qu'il existe de nombreux objets avec différents états de traitement. Lors de la création d'une arborescence de syntaxe abstraite, il est simplifié de créer l'interpréteur correspondant en fonction de la marque d'état, et il n'est pas nécessaire de construire un arbre.
De même, le mode interprète peut simuler la fonction de mise en œuvre du mode politique, la fonction du mode décorateur, etc., en particulier le processus de simulation de la fonction du mode décorateur et le processus de construction d'un arbre de syntaxe abstrait correspondra naturellement au processus de combinaison du décorateur.
Le mode interprète n'est généralement pas rapide (surtout très lent), et les erreurs de débogage sont difficiles (partie 1: bien que le débogage soit difficile, il réduit en fait la possibilité d'erreurs), mais ses avantages sont évidents. Il peut contrôler efficacement la complexité des interfaces entre les modules. Pour les fonctions qui ont une faible fréquence d'exécution mais une fréquence de code élevée suffisamment et sont très diverses, les interprètes sont très adaptés aux modes. De plus, l'interprète a un autre avantage moins notable, c'est-à-dire qu'il peut être commodément transversal et multiplateforme.
Avantages et inconvénients du mode interprète:
avantage:
1. Syntaxe facile à implémenter
En mode interprète, une règle de syntaxe est interprétée avec un objet interprète pour interpréter l'exécution. Pour la mise en œuvre de l'interprète, la fonction devient relativement simple. Il vous suffit de considérer la mise en œuvre de cette règle de syntaxe, et vous n'avez à vous soucier de rien d'autre. 2. Facile à développer une nouvelle syntaxe
C'est précisément en raison de la façon dont un objet interprète est responsable d'une règle de syntaxe que l'extension de la nouvelle syntaxe est très facile. La nouvelle syntaxe a été élargie et vous n'avez qu'à créer l'objet interprète correspondant et à utiliser ce nouvel objet d'interpréteur lors de la création d'une arborescence de syntaxe abstraite.
défaut:
Pas adapté à une syntaxe complexe
Si la syntaxe est particulièrement complexe, le travail de construction de l'arbre de syntaxe abstrait requis par le modèle d'interprète est très difficile, et il est possible de construire plusieurs arbres de syntaxe abstraits. Par conséquent, le modèle d'interprète ne convient pas à une syntaxe complexe. Il peut être préférable d'utiliser un analyseur de syntaxe ou un générateur de compilateur.
Quand l'utiliser?
Lorsqu'il y a un langage qui doit être interprété et exécuté, et que les phrases dans cette langue peuvent être représentées comme une arborescence de syntaxe abstraite, vous pouvez envisager d'utiliser le modèle d'interprète.
Lorsque vous utilisez le mode interprète, il existe deux autres fonctionnalités qui doivent être prises en compte. La première est que la syntaxe doit être relativement simple. La syntaxe trop responsable ne convient pas à l'utilisation du mode interprète. L'autre est que les exigences d'efficacité ne sont pas très élevées et que les exigences d'efficacité sont très élevées et ne conviennent pas à une utilisation.
L'introduction précédente était de savoir comment obtenir la valeur d'un seul élément et la valeur d'un seul élément. Voyons comment obtenir les valeurs de plusieurs éléments, ainsi que les valeurs des noms les unes des autres dans plusieurs éléments, et les tests précédents sont tous des arbres de syntaxe abstraits combinés artificiellement. Nous implémentons également l'analyseur simple suivant pour convertir des expressions conformes à la syntaxe définie ci-dessus en arbres de syntaxe abstraits de l'interprète implémenté ci-dessus: J'ai directement publié le code:
La copie de code est la suivante:
// Lire les valeurs de plusieurs éléments ou attributs
(fonction () {
/ **
* Contexte, utilisé pour contenir certaines informations globales requises par l'interprète
* @param {string} filepathName [chemin et nom du xml qui doit être lu]
* /
Contexte de fonction (filepathName) {
// plusieurs éléments qui ont été traités dans le précédent
this.preeles = [];
// Objet de document XML
this.Document = xmLutil.getRoot (filePathName);
}
Context.prototype = {
// réinitialiser le contexte
reinit: function () {
this.preeles = [];
},
/ **
* Méthodes d'utilisation du public de chaque expression
* Obtenez l'élément actuel en fonction du nom de l'élément parent et de l'élément actuel
* @param {élément} pele [élément parent]
* @param {String} eLename [Nom de l'élément actuel]
* @return {élément | null} [élément actuel trouvé]
* /
getNoweles: function (pele, elename) {
Var Elements = [];
var tempNodelist = pele.childnodes;
var nowele;
for (var i = 0, len = tempNodeList.length; i <len; i ++) {
if ((nowele = tempNodelist [i]). nodetype === 1) {
if (nowele.nodename === eLename) {
elements.push (nowele);
}
}
}
Éléments de retour;
},
getPreeles: function () {
Renvoyez ceci.preeles;
},
setPreeles: function (noweles) {
this.preeles = noweles;
},
getDocument: function () {
Renvoyez ce.Document;
}
};
// objet d'outil
// analyse XML pour obtenir l'objet de document correspondant
var xmlutil = {
getroot: function (filepathname) {
var parser = new DOMPARSER ();
var xmldom = parser.parsefromString ('<root id = "rootId"> <a> <b> <c name = "testc"> 12345 </c> <d id = "1"> d1 </ d> <d id = "2"> d2 </d> <d id = "3"> d3 </d> </ D3 id = "4"> d4 </d> </b> </a> </ root> ',' text / xml ');
retour xmldom;
}
};
/ **
* Les éléments sont utilisés comme interprètes correspondant à des non-terminaux pour interpréter et exécuter des éléments intermédiaires
* @param {String} eLename [Nom de l'élément]
* /
fonction ElementExpression (eLename) {
this.eles = [];
this.elename = eLename;
}
ElementExpression.prototype = {
adddele: fonction (eLename) {
this.eles.push (elename);
Retour Vrai;
},
RETI-REVEPELLE: fonction (ele) {
pour (var i = 0, len = this.eles.length; i <len; i ++) {
if (ele === this.eles [i]) {
this.eles.splice (i--, 1);
}
}
Retour Vrai;
},
Interpréter: fonction (contexte) {
// supprime d'abord l'élément actuel dans le contexte en tant qu'élément parent
// Trouvez l'élément XML correspondant au nom de l'élément actuel et remettez-le sur le contexte
var peles = context.getPreeles ();
var ele = null;
var noweles = [];
if (! peles.length) {
// indique que l'élément racine est maintenant obtenu
ele = context.getDocument (). documentElement;
peles.push (ele);
context.setpreeles (peles);
} autre {
var tempele;
pour (var i = 0, len = peles.length; i <len; i ++) {
Tempele = peles [i];
noweles = noweles.concat (context.getNoweles (tempele, this.elename));
// Arrêtez-vous si vous en trouvez un
if (noweles.length) casser;
}
context.setpreeles ([noweles [0]]);
}
var ss;
// boucle pour appeler la méthode d'interprétation de l'élément enfant
pour (var i = 0, len = this.eles.length; i <len; i ++) {
ss = this.eles [i] .interpret (context);
}
retour ss;
}
};
/ **
* Les éléments sont utilisés comme interprète correspondant au terminateur
* @param {String} Nom [Nom de l'élément]
* /
fonction elementTerminalexpression (name) {
this.elename = name;
}
Elementterminalexpression.prototype = {
Interpréter: fonction (contexte) {
var peles = context.getPreeles ();
var ele = null;
if (! peles.length) {
ele = context.getDocument (). documentElement;
} autre {
ele = context.getNoweles (peles [0], this.elename) [0];
}
// Obtenez la valeur de l'élément
retour ele.firstchild.nodevalue;
}
};
/ **
* L'attribut est utilisé comme interprète correspondant au terminateur
* @param {string} propname [nom de l'attribut]
* /
fonction Propertyterminalexpression (propName) {
this.propName = propName;
}
Propriététerminalexpression.prototype = {
Interpréter: fonction (contexte) {
// Obtenez directement la valeur de l'attribut d'élément dernier
return context.getPreeles () [0] .getAttribute (this.propName);
}
};
/ **
* Plusieurs attributs sont utilisés comme interprète correspondant au terminateur
* @param {string} propname [nom de l'attribut]
* /
fonction PropertySterMinalexpression (propName) {
this.propName = propName;
}
PropertySterMinalexpression.prototype = {
Interpréter: fonction (contexte) {
var eles = context.getPreeles ();
var ss = [];
pour (var i = 0, len = eles.length; i <len; i ++) {
ss.push (eles [i] .getAttribute (this.propname));
}
retour ss;
}
};
/ **
* Objet de traitement d'interprétation avec plusieurs éléments comme terminateurs
* @param {[type]} nom [Description]
* /
fonction ElementTerminAnalexpression (nom) {
this.elename = name;
}
Elementterminalexpression.prototype = {
Interpréter: fonction (contexte) {
var peles = context.getPreeles ();
var noweles = [];
pour (var i = 0, len = peles.length; i <len; i ++) {
noweles = noweles.concat (context.getNoweles (peles [i], this.elename));
}
var ss = [];
pour (i = 0, len = noweles.length; i <len; i ++) {
ss.push (noweles [i] .firstchild.nodevalue);
}
retour ss;
}
};
/ **
* Plusieurs éléments sont interprétés comme des non-terminaux
* /
fonction elementSExpression (name) {
this.elename = name;
this.eles = [];
}
ElementSExpression.prototype = {
Interpréter: fonction (contexte) {
var peles = context.getPreeles ();
var noweles = [];
pour (var i = 0, len = peles.length; i <len; i ++) {
noweles = noweles.concat (context.getNoweles (peles [i], this.elename));
}
context.setpreeles (noweles);
var ss;
for (i = 0, len = this.eles.length; i <len; i ++) {
ss = this.eles [i] .interpret (context);
}
retour ss;
},
addele: fonction (ele) {
this.eles.push (ele);
Retour Vrai;
},
RETI-REVEPELLE: fonction (ele) {
pour (var i = 0, len = this.eles.length; i <len; i ++) {
if (ele === this.eles [i]) {
this.eles.splice (i--, 1);
}
}
Retour Vrai;
}
};
void function () {
// "root / a / b / d $"
var c = nouveau contexte ('interprète.xml');
var root = new ElementExpression ('root');
var aele = new ElementExpression ('a');
var bele = new ElementExpression ('b');
var dele = new ElementTerMinalexpression ('d');
root.addele (aele);
aele.addele (Bele);
bele.addele (dele);
var ss = root.interpret (c);
pour (var i = 0, len = ss.length; i <len; i ++) {
Console.log ('D Valeur est =' + ss [i]);
}
} ();
void function () {
// a / b / d $ .id $
var c = nouveau contexte ('interprète.xml');
var root = new ElementExpression ('root');
var aele = new ElementExpression ('a');
var bele = new ElementExpression ('b');
var dele = new ElementSExpression ('D');
var prop = new PropertySterMinalexpression ('id');
root.addele (aele);
aele.addele (Bele);
bele.addele (dele);
dele.addele (PROP);
var ss = root.interpret (c);
pour (var i = 0, len = ss.length; i <len; i ++) {
console.log ('d La valeur de l'ID de propriété est =' + ss [i]);
}
} ();
// analyseur
/ **
* Idées de mise en œuvre de l'analyseur
* 1. Décomposer les expressions transmises par le client, les décomposer en éléments un par un et utiliser un modèle analytique correspondant pour encapsuler certaines informations sur cet élément.
* 2. Convertissez-le en objet d'analyse correspondant en fonction des informations de chaque élément.
* 3. Combinez ces objets d'analyse afin d'obtenir un arbre de syntaxe abstrait.
*
* Pourquoi ne fusionnez-vous pas 1 et 2, et décomposez-vous directement un élément et le convertissez-vous en objet d'analyseur correspondant?
* 1. Séparation fonctionnelle, ne compliquez pas les fonctions d'une méthode.
* 2. Pour une modification et une extension futures, la syntaxe est désormais simple, il n'y a donc pas grand-chose à considérer lors de la conversion en un objet d'analyseur, et il n'est pas difficile de convertir directement, mais si la syntaxe est compliquée, la conversion directe sera très désordonnée.
* /
/ **
* Utilisé pour encapsuler les attributs correspondants de chaque élément analysé
* /
fonction ParserModel () {
// si une seule valeur
this.singlevalue;
// que ce soit un attribut, soit un attribut ou un élément
this.propertyvalue;
// s'il faut terminer
this.end;
}
ParserModel.prototype = {
isEnd: function () {
Renvoyez ceci.end;
},
settend: function (end) {
this.end = end;
},
issingleValue: function () {
Renvoyez ceci.SingleValue;
},
setSingleValue: function (onevalue) {
this.singleValue = oneValue;
},
isPropertyValue: function () {
Renvoyez ce.propertyValue;
},
setPropertyValue: function (propriétéValue) {
this.propertyValue = PropertyValue;
}
};
var parser = function () {
Var Backlash = '/';
var dot = '.';
var dollar = '$';
// Enregistrez les noms des éléments qui doivent être analysés selon l'ordre de décomposition
var listele = null;
// Démarrez la première étape --------------------------------------------------------------------------------------------------------------------------
/ **
* Passez une expression de chaîne, puis analysez-la et combinez-la dans une syntaxe abstraite
* @param {String} expr [Décrivez l'expression de la chaîne pour prendre la valeur]
* @return {objet} [arborescence syntaxe abstraite correspondante]
* /
fonction parsemappath (expr) {
// Divisez d'abord la chaîne en fonction de "/"
var tokenizer = expr.split (contrecoup);
// Tableau des valeurs décomposées
var mappath = {};
var onepath, elename, propname;
var dotindex = -1;
for (var i = 0, len = tokenizer.length; i <len; i ++) {
onePath = tokenizer [i];
if (tokenizer [i + 1]) {
// il y a une autre valeur, ce qui signifie que ce n'est pas le dernier élément
// Selon la syntaxe actuelle, l'attribut doit être à la fin, donc ce n'est pas l'attribut.
SetParsepath (False, OnePath, False, Mappath);
} autre {
// c'est la fin
dotIndex = onePath.Indexof (dot);
if (dotindex> = 0) {
// Cela signifie que vous voulez obtenir la valeur de l'attribut, alors divisez-le en fonction de "."
// Le premier est le nom de l'élément, et le second est le nom d'attribut
eLename = onePath.Substring (0, dotIndex);
propname = onepath.substring (dotIndex + 1);
// L'élément devant la propriété n'est naturellement pas le dernier, et ce n'est pas la propriété
SetParsepath (false, elename, false, mappath);
// Définir les attributs. Selon la définition actuelle de syntaxe, l'attribut ne peut être le dernier que.
SetParsepath (true, propname, true, mappath);
} autre {
// Les instructions sont prises comme la valeur de l'élément et la valeur du dernier élément
SetParsepath (True, OnePath, False, Mappath);
}
casser;
}
}
retour Mappath;
}
/ **
* Définissez le nom de l'élément à analyser en fonction de l'emplacement et du nom décomposés
* @param {boolean} end [est-ce le dernier]
* @param {string} ele [nom d'élément]
* @param {boolean} PropertyValue [s'il faut prendre la propriété]
* @param {objet} Mappath [Définissez le nom de l'élément qui doit être analysé, et le tableau du modèle d'analyse correspondant à l'élément]
* /
fonction setParsepath (end, ele, propriétéValue, mappath) {
var pm = new ParserModel ();
pm.setend (fin);
// Si le symbole "$" n'est pas une valeur
PM.SetSingleValue (! (ele.indexof (Dollar)> = 0));
PM.SetProperTyValue (PropertyValue);
// supprimer "$"
ele = ele.replace (dollar, '');
Mappath [ele] = pm;
linele.push (ele);
}
// Démarrez la deuxième étape --------------------------------------------------------------------------------------------------------------------------
/ **
* Convertissez le nom de l'élément décomposé en l'objet interprète correspondant en fonction du modèle analytique correspondant.
* @param {objet} Mappath [Le nom de l'élément décomposé à analyser, et le modèle d'analyse correspondant à l'élément]
* @return {array} [Convertir chaque élément en un tableau d'objets d'interprète correspondants]
* /
fonction mappath2interpreter (mappath) {
var list = [];
var pm, clé;
var obj = null;
// Il est nécessaire de le convertir en objets interprètes dans l'ordre de décomposition
pour (var i = 0, len = listEle.length; i <len; i ++) {
key = listEle [i];
pm = mappath [key];
// pas le dernier
if (! pm.isend ()) {
if (pm.issinglevalue ())
// est une valeur, conversion
obj = new ElementExpression (key);
autre
// est plusieurs valeurs, conversion
obj = new ElementSExpression (key);
} autre {
// c'est le dernier
// est la valeur d'attribut
if (pm.ispropertyvalue ()) {
if (pm.issinglevalue ())
obj = new PropertyTerMinalexpression (clé);
autre
obj = new PropertySterMinalexpression (key);
// prenez la valeur de l'élément
} autre {
if (pm.issinglevalue ())
obj = new ElementTerMinalexpression (clé);
autre
OBJ = NOUVEAU Élémentsterminalexpression (clé);
}
}
list.push (obj);
}
Liste de retour;
}
// Démarrez la troisième étape --------------------------------------------------------------------------------------------------------------------------
/ **
* Construisez un arbre syntaxe abstrait
* @param {[type]} liste [Convertir chaque élément en un tableau d'objets d'interprète correspondants]
* @return {[type]} [Description]
* /
fonction buildTree (list) {
// Le premier objet, également l'objet retourné, est la racine de l'arbre de syntaxe abstrait
var returnReadxmlexpr = null;
// définir l'objet précédent
var prereadxmlexpr = null;
var readxml, ele, eles;
pour (var i = 0, len = list.length; i <len; i ++) {
readxml = list [i];
// Description est le premier élément
if (prereadxmlexpr === null) {
prereadxmlexpr = readxml;
returnReadxmlexpr = readxml;
// Ajouter l'élément à l'objet précédent et définir l'objet sur Olddre
// en tant que nœud parent de l'objet suivant
} autre {
if (prereadxmlexpr instanceof elementExpression) {
ele = prereadxmlexpr;
ele.addele (readxml);
prereadxmlexpr = readxml;
} else if (prereadxmlexpr instanceof elementSExpression) {
eles = prereadxmlexpr;
eles.addele (readxml);
prereadxmlexpr = readxml;
}
}
}
return returnReadxmlexpr;
}
retour {
// Méthode publique
Parse: fonction (expr) {
listEle = [];
var mappath = parsemappath (expr);
var list = Mappath2Interpreter (mappath);
return buildTree (liste);
}
};
} ();
void function () {
// prépare le contexte
var c = nouveau contexte ('interprète.xml');
// Obtenez l'arbre de syntaxe abstrait en l'analysant
var readxmlexpr = parser.parse ('root / a / b / d $ .id $');
// demande l'analyse et obtenir la valeur de retour
var ss = readxmlexpr.interpret (c);
console.log ('------------ analyse --------------');
pour (var i = 0, len = ss.length; i <len; i ++) {
console.log ('d La valeur de l'ID de propriété est =' + ss [i]);
}
Console.log ('--------------- Pared --------------');
// Si vous souhaitez utiliser le même contexte et analyser en continu, vous devez réinitialiser l'objet de contexte
C.Reinit ();
var readxmlexpr2 = parser.parse ('root / a / b / d $');
var ss2 = readxmlexpr2.interpret (c);
console.log ('------------ analyse --------------');
for (i = 0, len = ss2.length; i < len; i++) {
console.log('d的值是= ' + ss2[i]);
}
console.log('---------------parsed--------------');
c.reInit();
var readxmlExpr3 = Parser.parse('root/a/b/c');
var ss3 = readxmlExpr3.interpret(c);
console.log('------------parsing--------------');
console.log('c的name属性值是= ' + ss3);
console.log('---------------parsed--------------');
c.reInit();
var readxmlExpr4 = Parser.parse('root/a/b/c.name');
var ss4 = readxmlExpr4.interpret(c);
console.log('------------parseing--------------');
console.log('c的name属性值是= ' + ss4);
console.log('---------------parsed--------------');
}();
// 这样就实现了类似XPath的部分功能
// 没错,就类似于jQuery选择器的部分功能
}());
输出: d的值是= d1
d的值是= d2
d的值是= d3
d的值是= d4
d的属性id的值是= 1
d的属性id的值是= 2
d的属性id的值是= 3
d的属性id的值是= 4
------------parsing--------------
d的属性id的值是= 1
d的属性id的值是= 2
d的属性id的值是= 3
d的属性id的值是= 4
---------------parsed--------------
------------parsing--------------
d的值是= d1
d的值是= d2
d的值是= d3
d的值是= d4
---------------parsed--------------
------------parsing--------------
c的name属性值是= 12345
---------------parsed--------------
------------parseing--------------
c的name属性值是= testC
---------------parsed--------------