Shenma는 "통역 모드"입니까?
먼저 "GOF"를 열고 정의를 살펴 보겠습니다.
언어가 주어지면 문법의 표현을 정의 하고이 표현을 사용하여 언어로 문장을 해석하는 통역사를 정의하십시오.
처음에는 몇 가지 개념을 대중화해야합니다.
추상 구문 트리 :
통역사 패턴은 추상 구문 트리를 만드는 방법을 설명하지 않습니다. 문법 분석이 포함되지 않습니다. 추상 구문 트리는 테이블 중심의 구문 분석 프로그램에 의해 완료되거나 필기 (일반적으로 재귀 하강) 구문 분석 프로그램에 의해 만들어 지거나 클라이언트가 직접 제공 할 수 있습니다.
파서 :
클라이언트 호출에 필요한 표현을 설명하고 구문 분석 후 추상 구문 트리를 형성하는 프로그램을 말합니다.
통역사:
추상 구문 트리를 설명하고 각 노드의 해당 함수를 실행하는 프로그램을 나타냅니다.
통역사 패턴을 사용하는 중요한 전제 조건은 문법이라고도하는 문법 규칙 세트를 정의하는 것입니다. 이 문법의 규칙이 단순하거나 복잡한 지 여부에 관계없이 해당 기능을 분석하고 수행하기 때문에 이러한 규칙이 포함되어야합니다.
통역 모드의 구조 다이어그램과 설명을 살펴 보겠습니다.
AbstractExpression : 통역사의 인터페이스를 정의하고 통역사의 해석 작업에 동의합니다.
terminalexpression : terminalexpression은 구문 규칙에서 터미네이터와 관련된 작업을 구현하는 데 사용되며 더 이상 다른 통역사가 포함되지 않습니다. 조합 패턴이 추상 구문 트리를 만드는 데 사용되는 경우 조합 패턴의 잎 객체와 동일하며 여러 터미네이터 통역사가있을 수 있습니다.
Nonterminalexpression : 구문 규칙에서 비 터미널 관련 작업을 구현하는 데 사용되는 비 터미널 통역사. 일반적으로 통역사는 구문 규칙에 해당하며 다른 통역사를 포함 할 수 있습니다. 구성 패턴이 추상 구문 트리를 작성하는 데 사용되는 경우 구성 패턴의 조합 객체와 동일합니다. 비 터미널 통역사가 여러 개있을 수 있습니다.
컨텍스트 : 컨텍스트는 일반적으로 각 통역사 또는 공개 기능에 필요한 데이터를 포함합니다.
클라이언트 : 클라이언트는 통역사를 사용하는 클라이언트를 말합니다. 일반적으로 언어 구문에 따른 표현식은 통역사 객체에 의해 설명 된 추상 구문 트리로 변환되며 설명 작업이 호출됩니다.
여기서는 XML 예제를 사용하여 통역사 패턴을 이해합니다.
먼저 표현을 위해 간단한 문법을 설계해야합니다. 일반적으로 루트를 사용하여 루트 요소, ABC 등을 나타냅니다. 요소를 나타냅니다. 간단한 XML은 다음과 같습니다.
코드 사본은 다음과 같습니다.
<? xml version = "1.0"encoding = "utf-8">
<루트 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. 단일 요소의 값을 가져옵니다. 루트 요소에서 시작하여 값을 얻으려는 요소까지 시작하십시오. 요소의 중간은 루트 요소 전에 "/"로 분리되고 No "/"가 추가됩니다. 예를 들어, "root/a/b/c"표현은 루트 요소, 요소 A, 요소 B 및 요소 C에서 요소 C의 값을 얻는 것을 의미합니다.
2. 단일 요소의 속성 값을 얻으십시오. 물론 여러 속성이 있습니다. 값을 얻는 속성은 표현식의 마지막 요소의 속성이어야합니다. 추가하다 "." 마지막 요소 후에 속성의 이름을 추가하십시오. 예를 들어, "root/a/b/c.name"표현은 루트 요소, 요소 A, 요소 B, 요소 C의 이름 속성의 값을 얻는 것을 의미합니다.
3. 동일한 요소 이름의 값을 얻으십시오. 물론 여러 요소가 있습니다. 값을 얻는 요소는 표현식의 마지막 요소 여야하고 마지막 요소 후에 "$"를 추가해야합니다. 예를 들어, "root/a/b/d $"표현은 루트 요소 아래, A 요소 하에서 및 B 요소 하에서 여러 D 요소의 값의 수집을 나타냅니다.
4. 동일한 요소 이름으로 속성의 값을 얻으십시오. 물론 여러 가지가 있습니다. 속성 값을 얻는 요소는 표현식의 마지막 요소 여야하며 마지막 요소 후에 "$"를 추가해야합니다. 예를 들어, "root/a/b/d $ .id $"표현은 루트 요소 아래, A 요소 및 B 요소 아래의 여러 d 요소 ID 속성 값의 값을 나타냅니다.
추상 구문 트리에 해당하는 위의 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 [현재 요소 이름]
* @return {Element | NULL} [현재 요소가 발견되었습니다]
*/
getNowele : function (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)
Nowele을 반환하십시오.
}
널 리턴;
},
getPreele : function () {
reply.preele;
},
setPreele : function (preele) {
this.preele = preele;
},
getDocument : function () {
이것을 반환하십시오. 문서;
}
};
맥락에서, 나는 도구 객체 xmlutil을 사용하여 xmldom을 얻었습니다. 아래에서 나는 dom3의 dompaser를 사용하고 있습니다. 일부 브라우저는이를 지원하지 않을 수 있습니다. 기본 브라우저를 사용하십시오 :
코드 사본은 다음과 같습니다.
// 도구 객체
// 해당 문서 객체를 얻으려면 XML을 구문 분석합니다
var xmlutil = {
getRoot : function (filePathName) {
var parser = new domparser ();
var xmldom = parser.parsefrstring ( '<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;
}
요소 투성. 프로로 타입 = {
addele : 함수 (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);
}
진실을 반환하십시오.
},
해석 : 함수 (컨텍스트) {
// 먼저 컨텍스트에서 현재 요소를 부모 요소로 꺼냅니다.
// 현재 요소 이름에 해당하는 XML 요소를 찾고 컨텍스트로 다시 설정합니다.
var pele = context.getPreele ();
if (! pele) {
// 루트 요소가 이제 얻어 졌음을 나타냅니다
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 (컨텍스트);
}
// 마지막 통역사의 설명 결과를 반환합니다. 일반적으로 마지막 통역사는 터미네이터 통역사입니다.
반환 ss;
}
};
/**
* 요소는 터미네이터에 해당하는 통역사로 사용됩니다.
* @param {String} 이름 [요소 이름]
*/
함수 elementterminalexpression (name) {
this.elename = 이름;
}
ElementterminalExpression.prototype = {
해석 : 함수 (컨텍스트) {
var pele = context.getPreele ();
var ele = null;
if (! pele) {
ele = context.getDocument (). DocumentElement;
} 또 다른 {
ele = context.getNowele (pele, this.elename);
context.setpreele (ele);
}
// 요소의 값을 얻습니다
ele.firstchild.nodevalue를 반환합니다.
}
};
/**
* 속성은 터미네이터에 해당하는 통역사로 사용됩니다.
* @param {String} propname [속성의 이름]
*/
함수 property terminalexpression (propname) {
this.propname = propname;
}
property terminalexpression.prototype = {
해석 : 함수 (컨텍스트) {
// 마지막 요소 속성의 값을 직접 가져옵니다.
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 ele = new ElementExpression ( 'b');
var ele = new ElementterminalExpression ( 'C');
// 조합
root.addele (aele);
aele.addele (ele);
ele.addele (cele);
console.log ( 'c의 값은 =' + root.ternpret (c));
} ();
출력 : C의 값은 = 12345입니다
그런 다음 위의 코드를 사용하여 단일 요소의 속성 값을 얻습니다.
코드 사본은 다음과 같습니다.
void function () {
var c = 새로운 컨텍스트 ();
// d 요소의 ID 속성, 즉 다음 표현식의 값을 얻고 싶습니다. "a/b/c.name"
// 이번에는 c가 끝나지 않았으며 c를 요소 표현으로 수정해야합니다.
var root = new ElementExpression ( 'root');
var aele = new ElementExpression ( 'a');
var ele = new ElementExpression ( 'b');
var ele = 새로운 요소 표현 ( 'C');
var prop = new property terminalexpression ( 'name');
// 조합
root.addele (aele);
aele.addele (ele);
ele.addele (cele);
cele.addele (prop);
Console.log ( 'C의 속성 이름 값은 =' + root.ternpret (c));
// 동일한 컨텍스트를 사용하고 지속적으로 구문 분석하려면 컨텍스트 객체를 다시 설치해야합니다.
// 예를 들어, 속성 이름의 값을 다시 연속적으로 다시 구입해야합니다. 물론 요소를 재결합 할 수 있습니다.
// 동일한 컨텍스트가 사용되는 한 컨텍스트 객체를 다시 시작해야합니다.
C.reinit ();
console.log ( 'Reget C의 속성 이름 값은 =' + root.ternpret (c));
} ();
출력 : c의 속성 이름 값은 = testc is ac
설명하다:
1. 통역 모드 기능 :
통역사 패턴은 통역 객체를 사용하여 해당 구문 규칙을 표현하고 처리합니다. 일반적으로 통역사는 구문 규칙을 처리합니다. 이론적으로, 구문 호환 표현이 통역사 객체로 표시 될 수 있고 추상 구문 트리를 형성 할 수있는 한, 해석기 패턴을 사용하여 처리 할 수 있습니다.
2. 구문 규칙 및 통역사
구문 규칙과 통역사 사이에는 서신이 있습니다. 일반적으로 통역사는 구문 규칙을 처리하지만 그 반대는 사실이 아닙니다. 구문 규칙은 여러 해석 및 처리를 가질 수 있습니다. 즉, 구문 규칙은 여러 통역사에 해당 할 수 있습니다.
3. 문맥 공통성
컨텍스트는 인터프리터 모드에서 매우 중요한 역할을합니다. 컨텍스트가 모든 통역사에게 전달되기 때문입니다. 따라서 통역사의 상태는 문맥에서 저장 및 액세스 할 수 있습니다. 예를 들어, 이전 통역사는 상황에 일부 데이터를 저장할 수 있으며 후자의 통역사는 이러한 값을 얻을 수 있습니다.
또한 통역사 외부의 일부 데이터는 컨텍스트를 통해 전달 될 수 있지만 통역사는이를 필요로합니다.
컨텍스트에는 함수가 있습니다. 즉, 각 통역사 객체에서 호출 할 수있는 공통 기능을 얻기 위해 상속을 사용하는 대신 객체 조합과 유사한 모든 통역사 객체의 공통 기능을 제공 할 수 있습니다.
4. 누가 추상 구문 트리를 만들 것입니다
이전 예에서는 클라이언트 측에서 초록 구문 트리를 수동으로 구축하는 것이 매우 번거 롭지 만 해석기 모드에서는 기능 의이 부분이 관련되지 않으며 구성된 추상 구문 트리를 해석하고 처리하는 데 책임이 있습니다. 우리는 표현을 추상 구문 트리로 변환 할 수있는 파서를 제공 할 수 있음을 소개합니다.
또 다른 문제가 있습니다. 즉, 구문 규칙은 다중 통역 객체에 해당 할 수 있습니다. 즉, 동일한 요소가 여러 통역 객체로 변환 될 수 있습니다. 즉, 동일한 표현식이 불필요한 초록 구문 트리를 형성 할 수 있으며, 이는 초록 구문 트리를 구축하기가 어려워지고 워크로드가 매우 큽니다.
5. 운영을 설명 할 책임이있는 사람
추상 구문 트리가 정의되는 한, 통역사는 해석 및 실행을 담당해야합니다. 구문 규칙이 다르지만 통역사는 실행 구문 규칙을 해석하는 데 사용할 통역자 객체를 선택할 책임이 없습니다. 초록 구문 트리를 구축 할 때 통역사 선택 기능이 완료됩니다.
6. 통역 모드의 통화 순서
1) 컨텍스트 객체를 만듭니다
2) 여러 통역 객체를 만들고 추상 구문 트리를 결합합니다.
3) 통역 대상의 해석 작업을 호출하십시오
3.1) 문맥을 통해 통역사의 상태를 저장하고 액세스하십시오.
비 터미네이터 통역 객체의 경우 포함 된 서브 트리터 객체를 재귀 적으로 호출하십시오.
통역사 패턴의 본질 : *별도의 구현, 실행 해석 *
인터프리터 모듈은 통역사 객체를 사용하여 구문 규칙을 처리하여 복잡한 기능을 분리합니다. 그런 다음 실행 해야하는 기능을 선택하고 이러한 기능을 해석 및 실행 해야하는 추상 구문 트리로 결합합니다. 그런 다음 초록 구문 트리에 따라 실행을 해석하여 해당 기능을 구현합니다.
표면적으로 통역사 모드는 일반적으로 사용하지 않는 사용자 정의 구문 처리에 중점을 둡니다. 그러나 본질적으로 통역사 모드에 대한 아이디어는 분리, 캡슐화, 단순화이며 많은 모드와 동일합니다.
예를 들어, 통역 모드를 사용하여 상태 모드의 기능을 시뮬레이션 할 수 있습니다. 통역사 모드로 처리 할 구문이 하나의 상태 마크로 만 단순화되는 경우, 통역사는 상태의 처리 객체로 간주됩니다. 상태를 나타내는 동일한 구문의 경우, 사용하지 않은 통역사가 많이있을 수 있습니다. 즉, 처리 상태가 다른 많은 객체가 있습니다. 초록 구문 트리를 만들 때 상태 마크를 기반으로 해당 통역사를 만들도록 단순화되며 트리를 만들 필요가 없습니다.
마찬가지로, 인터프리터 모드는 정책 모드, 데코레이터 모드의 기능 등을 구현하는 기능, 특히 데코레이터 모드의 기능을 시뮬레이션하는 과정을 시뮬레이션 할 수 있으며, 추상 구문 트리를 구축하는 프로세스는 자연스럽게 데코레이터를 결합하는 프로세스에 해당합니다.
인터프리터 모드는 일반적으로 빠르지 않으며 (대부분 매우 느리게) 오류 디버깅이 어렵습니다 (1 부 : 디버깅이 어렵지만 실제로 오류 가능성을 줄입니다). 모듈 사이의 인터페이스의 복잡성을 효과적으로 제어 할 수 있습니다. 실행 주파수가 낮지 만 코드 주파수가 충분하고 매우 다양하고 매우 다양 한 기능의 경우 해석기가 모드에 매우 적합합니다. 또한 통역사는 또 다른 눈에 띄지 않는 이점이 있으며, 이는 편리하게 교차 및 교차 플랫폼 일 수 있다는 것입니다.
통역 모드의 장점과 단점 :
이점:
1. 구문을 쉽게 구현할 수 있습니다
인터프리터 모드에서 구문 규칙은 실행을 해석하기 위해 통역사 객체로 해석됩니다. 통역사의 구현을 위해 기능은 비교적 간단 해집니다. 이 구문 규칙의 구현 만 고려하면 다른 것에 대해 걱정할 필요가 없습니다. 2. 새로운 구문을 쉽게 확장 할 수 있습니다
통역사 객체가 새로운 구문을 확장하는 것이 매우 쉽다는 구문 규칙을 담당하는 방식 때문입니다. 새로운 구문이 확장되었으며 초록 구문 트리를 만들 때 해당 통역사 객체를 만들고이 새로운 통역 객체를 사용하면됩니다.
결점:
복잡한 구문에 적합하지 않습니다
구문이 특히 복잡한 경우, 통역사 패턴에 필요한 추상 구문 트리를 구축하는 작업은 매우 어렵고 여러 초록 구문 트리를 구축 할 수 있습니다. 따라서 통역사 패턴은 복잡한 구문에 적합하지 않습니다. 구문 분석기 또는 컴파일러 생성기를 사용하는 것이 좋습니다.
언제 사용해야합니까?
해석 및 실행이 필요한 언어가 있고 해당 언어의 문장이 추상 구문 트리로 표시 될 수 있으면 통역 패턴을 사용하는 것을 고려할 수 있습니다.
인터프리터 모드를 사용하는 경우 고려해야 할 다른 두 가지 기능이 있습니다. 하나는 구문이 비교적 간단해야한다는 것입니다. 너무 책임이있는 구문은 통역사 모드를 사용하는 데 적합하지 않습니다. 다른 하나는 효율 요구 사항이 그다지 높지 않고 효율 요구 사항이 매우 높으며 사용하기에 적합하지 않다는 것입니다.
이전 소개는 단일 요소의 값과 단일 요소 속성의 값을 얻는 방법이었습니다. 여러 요소의 값과 여러 요소에서 서로 이름의 값을 얻는 방법을 살펴 보겠습니다. 이전 테스트는 모두 인위적으로 결합 된 추상 구문 트리입니다. 또한 위에서 정의 된 구문을 준수하는 표현식을 변환하기 위해 다음과 같은 간단한 구문 분석기를 구현합니다.
코드 사본은 다음과 같습니다.
// 여러 요소 또는 속성의 값을 읽습니다
(기능 () {
/**
* 통역사가 요구하는 일부 전역 정보를 포함하는 데 사용되는 컨텍스트
* @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 [현재 요소 이름]
* @return {Element | NULL} [현재 요소가 발견되었습니다]
*/
getNoweles : function (pele, elename) {
var 요소 = [];
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);
}
}
}
리턴 요소;
},
getPreeles : function () {
reply.preeles;
},
setPreeles : function (noweles) {
this.preeles = noweles;
},
getDocument : function () {
이것을 반환하십시오. 문서;
}
};
// 도구 객체
// 해당 문서 객체를 얻으려면 XML을 구문 분석합니다
var xmlutil = {
getRoot : function (filePathName) {
var parser = new domparser ();
var xmldom = parser.parsefrstring ( '<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;
}
요소 투성. 프로로 타입 = {
addele : 함수 (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);
}
}
진실을 반환하십시오.
},
해석 : 함수 (컨텍스트) {
// 먼저 컨텍스트에서 현재 요소를 부모 요소로 꺼냅니다.
// 현재 요소 이름에 해당하는 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 (컨텍스트);
}
반환 ss;
}
};
/**
* 요소는 터미네이터에 해당하는 통역사로 사용됩니다.
* @param {String} 이름 [요소 이름]
*/
함수 elementterminalexpression (name) {
this.elename = 이름;
}
ElementterminalExpression.prototype = {
해석 : 함수 (컨텍스트) {
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 [속성의 이름]
*/
함수 property terminalexpression (propname) {
this.propname = propname;
}
property terminalexpression.prototype = {
해석 : 함수 (컨텍스트) {
// 마지막 요소 속성의 값을 직접 가져옵니다.
return context.getPreeles () [0] .getAttribute (this.propName);
}
};
/**
* 여러 속성이 터미네이터에 해당하는 통역사로 사용됩니다.
* @param {String} propname [속성의 이름]
*/
함수 propertysterminalexpression (propname) {
this.propname = propname;
}
Propertysterminalexpression.prototype = {
해석 : 함수 (컨텍스트) {
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]} 이름 [설명]
*/
함수 요소 terminalexpression (name) {
this.elename = 이름;
}
요소 terminalexpression.prototype = {
해석 : 함수 (컨텍스트) {
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 (이름) {
this.elename = 이름;
this.eles = [];
}
ElementSexpression.prototype = {
해석 : 함수 (컨텍스트) {
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 (컨텍스트);
}
반환 ss;
},
addele : 함수 (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 = new Context ( 'Interpreter.xml');
var root = new ElementExpression ( 'root');
var aele = new ElementExpression ( 'a');
var ele = new ElementExpression ( 'b');
var dele = 새로운 요소 terminalexpression ( 'd');
root.addele (aele);
aele.addele (ele);
ele.addele (Dele);
var ss = root.interpret (c);
for (var i = 0, len = ss.length; i <len; i ++) {
console.log ( 'd 값은 =' + ss [i]);
}
} ();
void function () {
// a/b/d $ .id $
var c = new Context ( 'Interpreter.xml');
var root = new ElementExpression ( 'root');
var aele = new ElementExpression ( 'a');
var ele = new ElementExpression ( 'b');
var dele = new ElementSexpression ( 'd');
var prop = new propertysterminalexpression ( 'id');
root.addele (aele);
aele.addele (ele);
ele.addele (Dele);
dele.addele (prop);
var ss = root.interpret (c);
for (var i = 0, len = ss.length; i <len; i ++) {
console.log ( 'd 속성 ID 값은 =' + ss [i]);
}
} ();
// 파서
/**
* 파서의 구현 아이디어
* 1. 클라이언트가 전달한 표현식을 분해하고이를 요소로 하나씩 분해하고 해당 분석 모델을 사용 하여이 요소에 대한 정보를 캡슐화하십시오.
* 2. 각 요소의 정보에 따라 해당 파서 개체로 변환합니다.
* 3. 추상 구문 트리를 얻으려면이 파서 객체를 결합하십시오.
*
* 왜 1과 2를 병합하고 요소를 직접 분해하여 해당 파서 개체로 변환하지 않습니까?
* 1. 기능적 분리, 방법의 기능을 너무 복잡하게 만들지 마십시오.
* 2. 향후 수정 및 확장의 경우 구문은 이제 간단하므로 파서 객체로 변환 할 때 고려해야 할 것이 거의 없으며 직접 변환하기가 어렵지 않지만 구문이 복잡해지면 직접 변환이 매우 지저분해질 것입니다.
*/
/**
* 각 구획 된 요소의 해당 속성을 캡슐화하는 데 사용됩니다.
*/
함수 parsermodel () {
// 단일 값 여부
this.singlevalue;
// 속성이든 속성이든 요소이든
this.propertyvalue;
// 종료 여부
이. 엔드;
}
parsermodel.prototype = {
isend : function () {
이 this.end를 반환하십시오.
},
설정 : 기능 (끝) {
this.end = 끝;
},
issinglevalue : function () {
replice.singlevalue;
},
setsingleValue : function (OneValue) {
this.singlevalue = OneValue;
},
ispropertyValue : function () {
이 is.propertyvalue;
},
setPropertyValue : function (propertyValue) {
this.propertyValue = propertyValue;
}
};
var parser = function () {
var backlash = '/';
var dot = '.';
var dollar = '$';
// 분해 순서에 따라 구문 분석 해야하는 요소의 이름을 기록합니다.
var listele = null;
// Start the first step --------------------------------------------------------------------------------------------------------------------------
/**
* 문자열 표현식으로 전달한 다음 구문 분석 한 후 추상 구문 트리에 결합하십시오.
* @param {string} expr [값을 취할 문자열 표현식을 설명]
* @return {object} [해당 초록 구문 트리]
*/
함수 parsemappath (expr) {
// 먼저 "/"에 따라 문자열을 나눕니다.
var tokenizer = expr.split (backlash);
// 분해 된 값 테이블
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);
}
부서지다;
}
}
Mappath를 반환합니다.
}
/**
* 분해 된 위치와 이름에 따라 요소 이름을 구문 분석 할 요소 이름을 설정합니다.
* @param {boolean} end [마지막인가]
* @param {String} ele [요소 이름]
* @param {boolean} propertyvalue [부동산을 가져갈지]
* @param {object} mappath [구문 분석 해야하는 요소의 이름과 요소에 해당하는 구문 분석 모델의 표를 설정]
*/
함수 setParsepath (End, Ele, PropertyValue, Mappath) {
var pm = 새로운 parsermodel ();
pm.setend (끝);
// 기호 "$"가 값이 아닌 경우
pm.setsinglevalue (! (ele.indexof (달러)> = 0);
PM.SetPropertyValue (PropertyValue);
// "$"제거
ele = ele.replace (달러, '');
Mappath [ele] = pm;
listele.push (ele);
}
// Start the second step --------------------------------------------------------------------------------------------------------------------------
/**
* 분해 된 요소 이름을 해당 분석 모델에 따라 해당 통역 객체로 변환합니다.
* @param {object} mappath [구문 분석 할 분해 된 요소 이름과 요소에 해당하는 구문 분석 모델]
* @return {array} [각 요소를 해당 인터프리터 개체 배열로 변환]
*/
함수 mappath2 interpreter (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 = 새로운 요소 표현 (키);
또 다른
// 여러 값, 변환입니다
obj = 새로운 요소 섹시움 (키);
} 또 다른 {
// 마지막 것입니다
// 속성 값입니다
if (pm.ispropertyValue ()) {
if (pm.issingleValue ())
OBJ = 새로운 PropertyTerminalExpression (키);
또 다른
obj = 새로운 PropertysterminalExpression (키);
// 요소의 값을 취하십시오
} 또 다른 {
if (pm.issingleValue ())
obj = 새로운 elementterminalexpression (키);
또 다른
obj = 새로운 요소 terminalexpression (key);
}
}
list.push (obj);
}
반환 목록;
}
// Start the third step --------------------------------------------------------------------------------------------------------------------------
/**
* 추상 구문 트리를 만듭니다
* @param {[type]} list [각 요소를 해당 통역 객체 배열로 변환]
* @return {[type]} [설명]
*/
함수 buildTree (목록) {
// 첫 번째 객체 인 반환 된 객체는 추상 구문 트리의 루트입니다.
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) {
preadxmlexpr = readxml;
returnReadXmlexpr = readxml;
// 이전 객체에 요소를 추가하고 개체를 Oldre로 설정합니다.
// 다음 객체의 부모 노드로
} 또 다른 {
if (prereadxmlexpr instanceof elementexpression) {
ele = preadxmlexpr;
ele.addele (readxml);
preadxmlexpr = readxml;
} else if (prereadxMlexpr instanceof elementSexpression) {
ELES = PREREADXMLEXPR;
eles.addele (readxml);
preadxmlexpr = readxml;
}
}
}
return returnreadxmlexpr;
}
반품 {
// 공개 방법
구문 분석 : 기능 (expr) {
listele = [];
var mappath = parsemappath (expr);
var list = mappath2 interpreter (mappath);
Return BuildTree (목록);
}
};
} ();
void function () {
// 컨텍스트를 준비합니다
var c = new Context ( 'Interpreter.xml');
// 구문 분석하여 추상 구문 트리를 가져옵니다
var readxmlexpr = parser.parse ( 'root/a/b/d $ .id $');
// 구문 분석을 요청하고 반환 값을 얻습니다
var ss = readxmlexpr.interpret (c);
Console.log ( '------------ 구문 분석 --------------');
for (var i = 0, len = ss.length; i <len; i ++) {
console.log ( 'd 속성 ID 값은 =' + 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--------------