Шенма - «режим интерпретатора»?
Давайте сначала откроем «GOF» и посмотрим на определение:
Учитывая язык, определите представление его грамматики и определите интерпретатора, который использует это представление для интерпретации предложений на языке.
До начала мне все еще нужно популяризировать несколько концепций:
Аннотация Синтаксис Дерево:
Паттерн интерпретатора не объясняет, как создать абстрактное синтаксисное дерево. Это не включает в себя грамматический анализ. Абстрактное синтаксисное дерево может быть завершено с помощью программы анализа синтаксиса, управляемой таблицей, или создано с помощью рукописной (обычно рекурсивного нисходящего) программы анализа синтаксиса или предоставлена непосредственно клиентом.
САНЧЕР:
Это относится к программе, которая описывает выражения, необходимые для клиента, и образует абстрактное синтаксисное дерево после анализа.
Устный переводчик:
Относится к программе, которая объясняет абстрактное синтаксисное дерево и выполняет соответствующие функции каждого узла.
Важной предпосылкой для использования шаблона интерпретатора является определение набора грамматических правил, также известных как грамматика. Независимо от того, являются ли правила этой грамматики простыми или сложными, эти правила должны быть включены, поскольку режим интерпретатора должен соответствующим образом анализировать и выполнять соответствующие функции.
Давайте посмотрим на диаграмму структуры и описание режима интерпретатора:
AbstractExpression: определяет интерфейс интерфейса и соглашается с операцией интерпретации интерпретатора.
Terminalexpression: Terminalexpression, используемый для реализации операций, связанных с терминатором в правилах синтаксиса, больше не содержит других переводчиков. Если комбинированный шаблон используется для создания абстрактного синтаксического дерева, он эквивалентен объекту листа в комбинированном шаблоне, и может быть несколько переводчиков терминатора.
Nonterminalexpression: некомминальный интерпретатор, используемый для реализации операций, не связанных с непомощными, в правилах синтаксиса. Обычно интерпретатор соответствует синтаксическому правилу и может содержать других переводчиков. Если шаблон композиции используется для построения абстрактного синтаксического дерева, он эквивалентен комбинированному объекту в паттерне композиции. Там может быть несколько не концевых переводчиков.
Контекст: контекст, обычно содержит данные, требуемые каждым интерпретатором или публичными функциями.
Клиент: клиент ссылается на клиента, который использует переводчика. Обычно выражения, сделанные в соответствии с синтаксисом языка, преобразуются в абстрактное синтаксисное дерево, описанное объектом интерпретатора, и затем называется операция пояснения.
Здесь мы используем пример XML, чтобы понять шаблон интерпретатора:
Во -первых, нам нужно спроектировать простую грамматику для выражения. Для общего назначения используйте root, чтобы представить корневой элемент, ABC и т. Д., Чтобы представить элемент. Простой XML выглядит следующим образом:
Кода -копия выглядит следующим образом:
<? xml version = "1.0" Encoding = "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>
Грамматика выражения конвенции заключается в следующем:
1. Получите значение одного элемента: начните с корневого элемента и вплоть до элемента, который вы хотите получить. Середина элемента разделена «/», а не «/» добавляется перед корневым элементом. Например, выражение «root/a/b/c» означает получение значений элемента C в элементе корневого, элемента A, элемента B и элемента c.
2. Получите значение атрибута одного элемента: конечно, есть несколько атрибутов. Атрибут для получения значения должен быть атрибутом последнего элемента выражения. Добавлять "." После последнего элемента, а затем добавьте имя атрибута. Например, выражение «root/a/b/c.name» означает получение значения атрибута имени корневого элемента, элемента A, элемента B, элемента c.
3. Получите значение одного имени элемента, конечно, есть несколько элементов. Элемент для получения значения должен быть последним элементом выражения и добавить «$» после последнего элемента. Например, выражение «root/a/b/d $» представляет собой сбор значений нескольких элементов D под корневым элементом, под элементом A и под элементом B.
4. Получите значение атрибута с одним именем элемента, конечно, есть несколько: элемент для получения значения атрибута должен быть последним элементом выражения и добавить «$» после последнего элемента. Например, выражение «root/a/b/d $ .id $» представляет собой сбор значений множественных атрибутов идентификаторов D -элементов D в элементе корневого элемента, под элементом A и под элементом B.
Приведенный выше XML, соответствующий абстрактному синтаксическому дереву, и возможная структура показана на рисунке:
Давайте посмотрим на конкретный код ниже:
1. Определите контекст:
Кода -копия выглядит следующим образом:
/**
* Контекст, используемый для содержания некоторой глобальной информации, требуемой интерпретатором
* @param {string} filePathName [Путь и имя XML, которое нужно прочитать]
*/
функция контекста (filePathName) {
// предыдущий обработанный элемент
this.preele = null;
// xml -объект документа
this.document = xmlutil.getroot (filePathName);
}
Context.prototype = {
// поврежденная контекст
Reinit: function () {
this.preele = null;
},
/**
* Методы общественного использования каждого выражения
* Получить текущий элемент в соответствии с именем родительского элемента и текущего элемента
* @param {element} pele [родительский элемент]
* @param {String} Elename [Current Element name]
* @return {element | null} [Найден текущий элемент]
*/
getNowele: function (pele, Elename) {
var tempnodelist = pele.childnodes;
var nowlele;
for (var i = 0, len = tempnodelist.length; i <len; i ++) {
if ((nowele = tempnodelist [i]). Nodetype === 1)
if (nowele.nodename === Elename)
вернуть Ноуле;
}
вернуть ноль;
},
getPreele: function () {
вернуть это. Preele;
},
setPreele: function (preele) {
this.preele = preele;
},
getDocument: function () {
вернуть это.document;
}
};
В контексте я использовал объект инструмента Xmlutil, чтобы получить XMLDOM. Ниже я использую Dompaser Dom3. Некоторые браузеры могут не поддерживать его. Пожалуйста, используйте базовый браузер:
Кода -копия выглядит следующим образом:
// объект инструмента
// parse xml, чтобы получить соответствующий объект документа
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> <d id = "4"> d4 </d> </b> </a> </root> ',' text/xml ');
вернуть Xmldom;
}
};
Вот код для переводчика:
Кода -копия выглядит следующим образом:
/**
* Элементы используются в качестве переводчиков, соответствующих неходным для интерпретации и выполнения промежуточных элементов
* @param {String} Elename [имя элемента]
*/
функция elementExpression (Elename) {
this.eles = [];
this.elename = Elename;
}
ElementExpression.prototype = {
addele: function (Elename) {
this.eles.push (Elename);
вернуть истину;
},
removeEle: function (ele) {
for (var i = 0, len = this.eles.length; i <len; i ++) {
if (ele === this.eles [i])
this.eles.splice (i--, 1);
}
вернуть истину;
},
интерпретация: function (context) {
// сначала вывести текущий элемент в контексте как родительский элемент
// Найти элемент XML, соответствующий текущему имени элемента, и установите его обратно в контекст
var pele = context.getPreele ();
if (! Пеле) {
// указывает, что корневой элемент теперь получен
context.setpreele (context.getDocument (). DocumentElement);
} еще {
// Получить текущий элемент на основе имени родительского элемента и элемента, который необходимо найти
var nowele = context.getnowele (pele, this.elename);
// Поместите в настоящее время извлеченный элемент в контекст
context.setpreele (nowele);
}
var ss;
// цикл, чтобы вызвать метод интерпретации дочернего элемента
for (var i = 0, len = this.eles.length; i <len; i ++) {
ss = this.eles [i] .Interpret (context);
}
// возвращать результат объяснения последнего переводчика. Как правило, последним переводчиком является переводчик терминатора.
вернуть SS;
}
};
/**
* Элементы используются в качестве интерпретатора, соответствующего терминатору
* @param {string} name [имя элемента]
*/
Function elementMerminalexPression (name) {
this.elename = name;
}
ElementTerminaleXpression.prototype = {
интерпретация: function (context) {
var pele = context.getPreele ();
var ele = null;
if (! Пеле) {
ele = context.getDocument (). DocumentElement;
} еще {
ele = context.getnowele (pele, this.elename);
context.setpreele (ele);
}
// Получить значение элемента
вернуть ele.firstchild.nodevalue;
}
};
/**
* Атрибут используется в качестве интерпретатора, соответствующего терминатору
* @param {string} propname [имя атрибута]
*/
Функция PropertyTmormInaleXpression (PropName) {
this.propname = propname;
}
PropertyTerminaleXpression.prototype = {
интерпретация: function (context) {
// Получить значение атрибута последнего элемента напрямую
return context.getPreele (). getattribute (this.propname);
}
};
Давайте сначала посмотрим, как использовать интерпретатора, чтобы получить значение одного элемента:
Кода -копия выглядит следующим образом:
void function () {
var c = новый контекст ();
// Хотите получить значение нескольких элементов D, то есть значение следующего выражения: "root/a/b/c"
// Во -первых, вам нужно построить абстрактное синтаксисное дерево для интерпретатора
var root = new ElementExpression ('root');
var aele = new ElementExpression ('a');
var bele = new elementexpression ('b');
var cele = new ElementMinaleXpression ('c');
// комбинация
root.addele (aele);
aele.addele (bele);
Bele.addele (Cele);
console.log ('claine is =' + root.interpret (c));
} ();
Вывод: значение C равно = 12345
Затем мы используем приведенный выше код, чтобы получить значение атрибута одного элемента:
Кода -копия выглядит следующим образом:
void function () {
var c = новый контекст ();
// Хотите получить атрибут идентификатора элемента D, то есть значение следующего выражения: «A/b/c.name»
// на этот раз c не закончится, и вам нужно изменить C на 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');
// комбинация
root.addele (aele);
aele.addele (bele);
Bele.addele (Cele);
cele.addele (prop);
console.log ('cloge name и name свойства C is =' + root.interpret (c));
// Если вы хотите непрерывно использовать один и тот же контекст и анализ, вам необходимо повторно реализовать контекстный объект
// Например, вам необходимо повторно получить значение имени атрибута снова последовательно, конечно, вы можете рекомбинировать элементы
// повторно устроен, пока используется один и тот же контекст, объект контекста должен быть повторно инициализован
C.Reinit ();
console.log ('' Значение имени свойства REGET C IS = ' + root.Interpret (c));
} ();
Вывод: значение имени атрибута C IS = TESTC Извлеките значение имени атрибута C IS = TESTC
объяснять:
1. Функция режима интерпретатора:
Паттерн интерпретатора использует объекты интерпретатора для представления и обработки соответствующих правил синтаксиса. Как правило, интерпретатор обрабатывает правило синтаксиса. Теоретически, до тех пор, пока выражения синтаксиса могут быть представлены объектом интерпретатора и могут образовывать абстрактное синтаксисное дерево, для его обработки можно использовать шаблон интерпретатора.
2. Синтаксические правила и переводчики
Существует соответствие между правилами синтаксиса и переводчиками. Как правило, интерпретатор обрабатывает правило синтаксиса, но наоборот не соответствует действительности. Правило синтаксиса может иметь множественные интерпретации и обработку, то есть синтаксическое правило может соответствовать нескольким интерпретаторам.
3. Контекст общности
Контекст играет очень важную роль в режиме интерпретатора. Потому что контекст передается всем переводчикам. Следовательно, состояние интерпретатора может храниться и получить доступ в контексте. Например, предыдущий интерпретатор может сохранить некоторые данные в контексте, и последний интерпретатор может получить эти значения.
Кроме того, некоторые данные вне интерпретатора могут быть переданы через контекст, но переводчик нуждается в этом, и некоторые глобальные публичные данные.
В контексте также существует функция, которая заключается в том, что она может обеспечить общие функции всех объектов интерпретатора, аналогичных комбинациям объектов, а не использование наследования для получения общих функций, которые могут быть вызваны в каждом объекте интерпретатора.
4. Кто построит абстрактное синтаксисное дерево
В предыдущем примере очень трудно вручную построить абстрактное синтаксисное дерево на стороне клиента, но в режиме интерпретатора эта часть функции не задействована, и оно отвечает только за интерпретацию и обработку построенного абстрактного синтаксического дерева. Мы представим, что мы можем предоставить анализатор для преобразования выражений в абстрактные синтаксисные деревья.
Существует другая проблема, то есть синтаксическое правило может соответствовать нескольким объектам интерпретатора, то есть один и тот же элемент может быть преобразован в множество объектов интерпретатора, что означает, что одно и то же выражение может образовывать ненужное дерево с абстрактным синтаксисом, что также затрудняет создание абстрактного синтаксисного дерева, а рабочая нагрузка очень большая.
5. Кто отвечает за объяснение операции
Пока определено абстрактное синтаксисное дерево, интерпретатор должен нести ответственность за интерпретацию и выполнение. Хотя существуют разные правила синтаксиса, интерпретатор не несет ответственности за выбор того, какой объект интерпретатора использовать для интерпретации правил синтаксиса выполнения. Функция выбора интерпретатора завершена при создании абстрактного синтаксического дерева.
6. Порядок вызовов режима интерпретатора
1) Создать контекстный объект
2) Создать несколько объектов интерпретатора и комбинировать абстрактные синтаксические деревья
3) Призывать операцию интерпретации объекта интерпретатора
3.1) Хранить и получить доступ к состоянию интерпретатора через контекст.
Для объектов интерпретатора, не являющихся концертами, рекурсивно вызовите объект Subinterpreter, который он содержит.
Суть шаблона интерпретатора: *Отдельная реализация, интерпретация выполнения *
Модуль интерпретатора использует объект интерпретатора для обработки правила синтаксиса для разделения сложных функций; Затем выбирает функции, которые необходимо выполнять, и объединяет эти функции в абстрактное синтаксисное дерево, которое необходимо интерпретировать и выполнять; Затем интерпретирует выполнение в соответствии с абстрактным синтаксическим деревом для реализации соответствующих функций.
На первый взгляд, режим интерпретатора фокусируется на обработке пользовательского синтаксиса, который мы обычно не используем; Но, по сути, идея режима интерпретатора заключается в разделении, инкапсуляции, упрощении и такой же, как и многие режимы.
Например, режим интерпретатора может использоваться для моделирования функции режима состояния. Если синтаксис, который обрабатывается режимом интерпретатора, упрощается только до одной отметки состояния, интерпретатор рассматривается как объект обработки для состояния. Для того же синтаксиса, представляющего состояние, может быть много неиспользованных переводчиков, то есть есть много объектов с различными состояниями обработки. При создании абстрактного синтаксического дерева он упрощен для создания соответствующего интерпретатора на основе отметки состояния, и нет необходимости строить дерево.
Аналогичным образом, режим интерпретатора может имитировать функцию реализации режима политики, функции режима декоратора и т. Д., В частности, процесс моделирования функции режима декоратора и процесса создания абстрактного синтаксического дерева, естественно, будет соответствовать процессу объединения декоратора.
Режим интерпретатора обычно не быстрый (в основном очень медленная), а отладка ошибок затруднена (часть 1: Хотя отладка сложна, это фактически снижает вероятность ошибок), но его преимущества очевидны. Он может эффективно контролировать сложность интерфейсов между модулями. Для функций, которые имеют низкую частоту выполнения, но высокую частоту кода достаточно, и очень разнообразны, переводчики очень подходят для режимов. Кроме того, интерпретатор имеет еще одно менее заметное преимущество, которое состоит в том, что он может быть удобно межязычным и кроссплатформенным.
Преимущества и недостатки режима интерпретатора:
преимущество:
1. Легко реализовать синтаксис
В режиме интерпретатора правило синтаксиса интерпретируется с помощью объекта интерпретатора для интерпретации выполнения. Для реализации интерпретатора функция становится относительно простой. Вам нужно только рассмотреть реализацию этого правила синтаксиса, и вам не нужно беспокоиться ни о чем другом. 2. Легко расширить новый синтаксис
Именно из -за того, как объект интерпретатора отвечает за синтаксисное правило, что расширение нового синтаксиса очень прост. Новый синтаксис был расширен, и вам нужно только создать соответствующий объект интерпретатора и использовать этот новый объект интерпретатора при создании абстрактного синтаксического дерева.
недостаток:
Не подходит для сложного синтаксиса
Если синтаксис особенно сложный, работа по созданию абстрактного синтаксического дерева, требуемого шаблоном интерпретатора, очень сложна, и можно построить несколько абстрактных синтаксических деревьев. Следовательно, шаблон интерпретатора не подходит для сложного синтаксиса. Лучше использовать синтаксис -анализатор или генератор компилятора.
Когда его использовать?
Когда есть язык, который необходимо интерпретировать и выполнять, и предложения на этом языке могут быть представлены как абстрактное синтаксисное дерево, вы можете рассмотреть возможность использования шаблона интерпретатора.
При использовании режима интерпретатора есть две другие функции, которые необходимо учитывать. Одним из них является то, что синтаксис должен быть относительно простым. Синтаксис, который слишком ответственен, не подходит для использования режима интерпретатора. Другим является то, что требования к эффективности не очень высоки, а требования к эффективности очень высоки, и это не подходит для использования.
Предыдущим введением было то, как получить значение одного элемента и значение атрибута одного элемента. Давайте посмотрим, как получить значения нескольких элементов, а также значения имен друг друга в нескольких элементах, и предыдущие тесты представляют собой искусственно комбинированные абстрактные синтаксисные деревья. Мы также реализуем следующий простой анализатор для преобразования выражений, которые соответствуют синтаксису, определенному выше, в абстрактные синтаксические деревья интерпретатора, реализованного выше: я непосредственно опубликовал код:
Кода -копия выглядит следующим образом:
// Читать значения нескольких элементов или атрибутов
(function () {
/**
* Контекст, используемый для содержания некоторой глобальной информации, требуемой интерпретатором
* @param {string} filePathName [Путь и имя XML, которое нужно прочитать]
*/
функция контекста (filePathName) {
// несколько элементов, которые были обработаны в предыдущем
this.preeles = [];
// xml -объект документа
this.document = xmlutil.getroot (filePathName);
}
Context.prototype = {
// поврежденная контекст
Reinit: function () {
this.preeles = [];
},
/**
* Методы общественного использования каждого выражения
* Получить текущий элемент в соответствии с именем родительского элемента и текущего элемента
* @param {element} pele [родительский элемент]
* @param {String} Elename [Current Element name]
* @return {element | null} [Найден текущий элемент]
*/
getNoweles: function (pele, Elename) {
var elements = [];
var tempnodelist = pele.childnodes;
var nowlele;
for (var i = 0, len = tempnodelist.length; i <len; i ++) {
if ((nowele = tempnodelist [i]). Nodetype === 1) {
if (nowele.nodename === Elename) {
elements.push (nowele);
}
}
}
возвращаемые элементы;
},
getPreeles: function () {
вернуть это. Preeles;
},
SetPreeles: function (noweles) {
this.preeles = noweles;
},
getDocument: function () {
вернуть это.document;
}
};
// объект инструмента
// parse xml, чтобы получить соответствующий объект документа
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> <d id = "4"> d4 </d> </b> </a> </root> ',' text/xml ');
вернуть Xmldom;
}
};
/**
* Элементы используются в качестве переводчиков, соответствующих неходным для интерпретации и выполнения промежуточных элементов
* @param {String} Elename [имя элемента]
*/
функция elementExpression (Elename) {
this.eles = [];
this.elename = Elename;
}
ElementExpression.prototype = {
addele: function (Elename) {
this.eles.push (Elename);
вернуть истину;
},
removeEle: function (ele) {
for (var i = 0, len = this.eles.length; i <len; i ++) {
if (ele === this.eles [i]) {
this.eles.splice (i--, 1);
}
}
вернуть истину;
},
интерпретация: function (context) {
// сначала вывести текущий элемент в контексте как родительский элемент
// Найти элемент XML, соответствующий текущему имени элемента, и установите его обратно в контекст
var peles = context.getPreeles ();
var ele = null;
var noweles = [];
if (! peles.length) {
// указывает, что корневой элемент теперь получен
ele = context.getDocument (). DocumentElement;
peles.push (ele);
context.setpreeles (peles);
} еще {
var tempele;
for (var i = 0, len = peles.length; i <len; i ++) {
tempele = peles [i];
noweles = noweles.concat (context.getnoweles (tempele, this.elename));
// остановиться, если вы найдете один
if (noweles.length) перерыв;
}
context.setpreeles ([noweles [0]]);
}
var ss;
// цикл, чтобы вызвать метод интерпретации дочернего элемента
for (var i = 0, len = this.eles.length; i <len; i ++) {
ss = this.eles [i] .Interpret (context);
}
вернуть SS;
}
};
/**
* Элементы используются в качестве интерпретатора, соответствующего терминатору
* @param {string} name [имя элемента]
*/
Function elementMerminalexPression (name) {
this.elename = name;
}
ElementTerminaleXpression.prototype = {
интерпретация: function (context) {
var peles = context.getPreeles ();
var ele = null;
if (! peles.length) {
ele = context.getDocument (). DocumentElement;
} еще {
ele = context.getnoweles (peles [0], this.elename) [0];
}
// Получить значение элемента
вернуть ele.firstchild.nodevalue;
}
};
/**
* Атрибут используется в качестве интерпретатора, соответствующего терминатору
* @param {string} propname [имя атрибута]
*/
Функция PropertyTmormInaleXpression (PropName) {
this.propname = propname;
}
PropertyTerminaleXpression.prototype = {
интерпретация: function (context) {
// Получить значение атрибута последнего элемента напрямую
return context.getPreeles () [0] .getAttribute (this.propname);
}
};
/**
* Несколько атрибутов используются в качестве интерпретатора, соответствующего терминатору
* @param {string} propname [имя атрибута]
*/
Функция Propertysterminalexpression (PropName) {
this.propname = propname;
}
Propertysterminalexpression.prototype = {
интерпретация: function (context) {
var eles = context.getPreeles ();
var ss = [];
for (var i = 0, len = eles.length; i <len; i ++) {
ss.push (eles [i] .getattribute (this.propname));
}
вернуть SS;
}
};
/**
* Объект обработки интерпретации с несколькими элементами в качестве терминаторов
* @param {[type]} имя [Описание]
*/
Функция Elementmerminalexpression (имя) {
this.elename = name;
}
Elementmerminalexpression.prototype = {
интерпретация: function (context) {
var peles = context.getPreeles ();
var noweles = [];
for (var i = 0, len = peles.length; i <len; i ++) {
noweles = noweles.concat (context.getnoweles (peles [i], this.elename));
}
var ss = [];
for (i = 0, len = noweles.length; i <len; i ++) {
ss.push (noweles [i] .firstchild.nodevalue);
}
вернуть SS;
}
};
/**
* Многочисленные элементы интерпретируются как не-концевые
*/
функция elementSexpression (name) {
this.elename = name;
this.eles = [];
}
Elementsexpression.prototype = {
интерпретация: function (context) {
var peles = context.getPreeles ();
var noweles = [];
for (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);
}
вернуть SS;
},
addele: function (ele) {
this.eles.push (ele);
вернуть истину;
},
removeEle: function (ele) {
for (var i = 0, len = this.eles.length; i <len; i ++) {
if (ele === this.eles [i]) {
this.eles.splice (i--, 1);
}
}
вернуть истину;
}
};
void function () {
// "root/a/b/d $"
var c = новый контекст ('interpreter.xml');
var root = new ElementExpression ('root');
var aele = new ElementExpression ('a');
var bele = new elementexpression ('b');
var dele = new Elementmerminalexpression ('d');
root.addele (aele);
aele.addele (bele);
Bele.addele (Dele);
var ss = root.interpret (c);
for (var i = 0, len = ss.length; i <len; i ++) {
console.log ('d value is =' + ss [i]);
}
} ();
void function () {
// a/b/d $ .id $
var c = новый контекст ('interpreter.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);
for (var i = 0, len = ss.length; i <len; i ++) {
console.log ('D Значение идентификатора свойства is =' + ss [i]);
}
} ();
// анализатор
/**
* Идеи реализации анализатора
* 1. Разместите выражения, передаваемые клиентом, разлагайте их на элементы один за другим и используйте соответствующую аналитическую модель, чтобы инкапсулировать некоторую информацию об этом элементе.
* 2. Преобразовать его в соответствующий объект анализатора на основе информации каждого элемента.
* 3. Объедините эти объекты анализатора, чтобы получить абстрактное синтаксисное дерево.
*
* Почему бы вам не слияние 1 и 2, и напрямую разложить элемент и преобразовать его в соответствующий объект анализатора?
* 1. Функциональное разделение, не усложняйте функции метода.
* 2. Для будущей модификации и расширения синтаксис теперь прост, поэтому при преобразовании в объект анализатора мало что нужно учитывать, и не сложно преобразовать напрямую, но если синтаксис сложный, прямое преобразование будет очень грязным.
*/
/**
* Используется для инкапсуляции соответствующих атрибутов каждого проанализированного элемента
*/
функция parsermodel () {
// будь единственное значение
это.
// будь то атрибут, либо атрибут, либо элемент
this.propertyValue;
//Ть прекратить
это.
}
Parsermodel.prototype = {
iSend: function () {
вернуть это.
},
setend: function (end) {
this.end = end;
},
issinglevalue: function () {
вернуть это.
},
setsinglevalue: function (onevalue) {
это.
},
ispropertyValue: function () {
вернуть это. PropertyValue;
},
setPropertyValue: function (PropertyValue) {
this.propertyValue = PropertyValue;
}
};
var parser = function () {
var backlash = '/';
var dot = '.';
var dollar = '$';
// Записать имена элементов, которые необходимо проанализировать в соответствии с порядком разложения
var listele = null;
// запустить первый шаг ----------------------------------------------------------------------------------------------------------------------------------------------------------
/**
* Пропустите строковое выражение, а затем проанализируйте его и объедините в абстрактное синтаксисное дерево
* @param {string} expr [описать выражение строки, чтобы взять значение]
* @return {Object} [Соответствующее абстрактное синтаксисное дерево]
*/
Функция parsemappath (expr) {
// сначала разделить строку в соответствии с "/"
var tokenizer = expr.split (обратная реакция);
// таблица разложенных значений
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]) {
// есть еще одно значение, что означает, что это не последний элемент
// Согласно текущему синтаксису, атрибут должен быть в конце, так что это не атрибут.
SetParsePath (false, OnePath, False, Mappath);
} еще {
// это конец
dotindex = onepath.indexof (dot);
if (dotindex> = 0) {
// это означает, что вы хотите получить значение атрибута, поэтому разделите его в соответствии с «».
// Первый - это имя элемента, а второе - имя атрибута
Elename = OnePath.Substring (0, DotIndex);
PropName = OnePath.Substring (DotIndex + 1);
// элемент перед собственностью, естественно, не последний, и не является собственностью
SetParsepath (false, Elename, false, Mappath);
// установить атрибуты. Согласно текущему определению синтаксиса, атрибут может быть только последним.
SetParsepath (True, Propname, True, Mappath);
} еще {
// инструкции принимаются как значение элемента и значение последнего элемента
SetParsepath (True, OnePath, False, Mappath);
}
перерыв;
}
}
вернуть Маппат;
}
/**
* Установите имя элемента, которое будет проанализировано в соответствии с разложенным местоположением и названием
* @param {boolean} end [это последний]
* @param {string} ele [имя элемента]
* @param {boolean} propertyvalue [будь то собственность]
* @param {Object} mappath [Установите имя элемента, который необходимо проанализировать, и таблица модели анализа, соответствующая элементу]
*/
Функция setParsepath (end, ele, propertyvalue, mappath) {
var pm = new parsermodel ();
pm.setend (end);
// Если символ "$" не является значением
pm.setsinglevalue (! (ele.indexof (доллар)> = 0));
PM.SetPropertyValue (PropertyValue);
// Удалить "$"
ele = ele.replace (доллар, '');
Маппат [ele] = pm;
Listele.push (ele);
}
// запустить второй шаг ----------------------------------------------------------------------------------------------------------------------------------------------------------
/**
* Преобразовать имя разложенного элемента в соответствующий объект интерпретатора в соответствии с соответствующей аналитической моделью.
* @param {Object} mappath [разложенное имя элемента, которое будет проанализировано, и модель анализа, соответствующая элементу]
* @return {Array} [преобразовать каждый элемент в массив соответствующих объектов интерпретатора]
*/
функция mappath2interpreter (mappath) {
var list = [];
var pm, ключ;
var obj = null;
// необходимо преобразовать его в объекты интерпретатора в порядке разложения
for (var i = 0, len = listele.length; i <len; i ++) {
key = listele [i];
pm = mappath [ключ];
// не последний
if (! pm.isend ()) {
if (pm.issinglevalue ())
// это значение, конверсия
obj = new ElementExpression (ключ);
еще
// - многочисленные значения, преобразование
obj = new elementsexpression (ключ);
} еще {
// это последний
// это значение атрибута
if (pm.ispropertyvalue ()) {
if (pm.issinglevalue ())
obj = new PropertyTerminaleXpression (ключ);
еще
obj = new Propertysterminalexpression (Key);
// возьмите значение элемента
} еще {
if (pm.issinglevalue ())
obj = new elementmerminalexpression (ключ);
еще
obj = new Elementmerminalexpression (ключ);
}
}
list.push (obj);
}
вернуть список;
}
// запустить третий шаг ------------------------------------------------------------------------------------------------------------------------------------------------------
/**
* Построить абстрактное синтаксическое дерево
* @param {[type]} список [преобразовать каждый элемент в массив соответствующих объектов интерпретатора]
* @return {[type]} [Описание]
*/
функция BuildTree (List) {
// Первый объект, также возвращенный объект, является корнем абстрактного синтаксического дерева
var returnReadxmlexpr = null;
// Определить предыдущий объект
var prereadxmlexpr = null;
var readxml, ele, eles;
for (var i = 0, len = list.length; i <len; i ++) {
readxml = list [i];
// Описание - первый элемент
if (prereadxmlexpr === null) {
prereadxmlexpr = readxml;
returnReadXmlexpr = readxml;
// Добавить элемент в предыдущий объект и установить объект в Oldre
// как родительский узел следующего объекта
} еще {
if (prereadxmlexpr Encementof elementExpression) {
ele = prereadxmlexpr;
ele.addele (readxml);
prereadxmlexpr = readxml;
} else if (prereadxmlexpr exanceof elementsexpression) {
eles = prereadxmlexpr;
eles.addele (readxml);
prereadxmlexpr = readxml;
}
}
}
return returnReadxmlexpr;
}
возвращаться {
// публичный метод
parse: function (expr) {
listele = [];
var mappath = parsemappath (expr);
var list = mappath2interpreter (mappath);
вернуть BuildTree (список);
}
};
} ();
void function () {
// подготовить контекст
var c = новый контекст ('interpreter.xml');
// Получить абстрактное синтаксисное дерево, анализируя его
var readxmlexpr = parser.parse ('root/a/b/d $ .id $');
// Запрос на анализ и получить возвращаемое значение
var ss = readxmlexpr.interpret (c);
console.log ('------------ SAINING --------------');
for (var i = 0, len = ss.length; i <len; i ++) {
console.log ('D Значение идентификатора свойства is =' + ss [i]);
}
console.log ('--------------- Проанализирован --------------');
// Если вы хотите непрерывно использовать один и тот же контекст и анализ, вам необходимо повторно реализовать контекстный объект
C.Reinit ();
var readxmlexpr2 = parser.parse ('root/a/b/d $');
var ss2 = readxmlExpr2.interpret(c);
console.log('------------parsing--------------');
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--------------