표현식 관리자 (Expression Manager)
From LimeSurvey Manual
빠른 시작 튜토리얼
개요
설문조사를 사용자 지정할 때는 일반적으로 다음을 지정할 방법이 필요합니다.
- 탐색/분기 - 응답자의 응답에 따라 질문이 표시되는 순서를 변경합니다.
- 맞춤화/파이핑 - 질문을 표현하는 방식(예: 이전 응답 참조, 응답자의 수나 성별에 따른 문장 활용)이나 사용자 지정 보고서(예: 평가 점수 또는 맞춤형 조언)를 생성하는 방식입니다.
- 유효성 검사 - 응답이 최솟값 및 최댓값, 입력 패턴 일치 등 특정 기준을 충족하는지 확인합니다.
Expression Manager(EM)는 이러한 각 기능의 논리를 직관적으로 지정할 수 있는 방법을 제공합니다. 함수를 호출하는 경우에도 표준 수학 방정식으로 작성할 수 있는 거의 모든 것이 유효한 표현식입니다. 현재 EM은 80개의 함수를 제공하며, 더 많은 함수를 지원하도록 쉽게 확장할 수 있습니다. 또한 SGQA 이름 대신 사람이 읽을 수 있는 변수 이름으로 변수에 접근할 수 있습니다.
다음 섹션에서는 Expression Manager가 사용되는 주요 위치를 보여 줍니다.
관련성 (탐색/분기 제어)
일부 설문조사에서는 "Goto 논리"를 사용합니다. 예를 들어 질문 1에 C 옵션으로 응답하면 질문 5로 이동하는 방식입니다. 이 방식은 유효성을 검사하기 어렵고 질문 순서를 변경할 때 쉽게 깨지기 때문에 매우 제한적입니다. EM은 불리언 관련성 수식을 사용하여 질문이 유효할 수 있는 모든 조건을 지정합니다. 질문이 관련성이 있으면 질문이 표시되고, 그렇지 않으면 해당 없음 상태가 되며 데이터베이스에는 NULL 값이 저장됩니다. 이는 조건 편집기에서 할 수 있는 것과 비슷하지만, EM에서는 훨씬 더 복잡하고 강력한 기준을 쉽게 지정할 수 있습니다(또한 SGQA 명명 대신 변수 이름을 사용할 수 있습니다).
이 이미지는 설문조사의 관련성 논리를 검토하는 한 가지 방법을 보여 줍니다. 체질량지수(BMI)를 계산하는 예입니다. 관련성 수식은 변수 이름(녹색) 바로 뒤의 대괄호 안에 표시됩니다. 따라서 weight, weight_units, height, height_units의 관련성은 모두 1이며, 이는 해당 질문이 항상 표시된다는 뜻입니다. 반면 BMI의 관련성은 {!is_empty(height) and !is_empty(weight)}이며, 이는 응답자가 height와 weight 값을 모두 입력한 경우에만 BMI가 계산된다는 의미입니다(따라서 0으로 나누기 오류의 위험을 피할 수 있습니다). 또한 Report 질문은 응답자가 네 가지 주요 질문(height, height_units, weight, weight_units)에 모두 답변한 경우에만 표시됩니다.
관련성은 다음 위치에서 확인하고 편집할 수 있습니다.
질문 수준 관련성 보기 / 편집
이 수식은 체질량지수(BMI)를 계산합니다. 응답자가 먼저 키와 몸무게를 입력한 경우에만 표시됩니다.
BMI 질문의 편집 화면입니다.
관련성 수식을 입력할 때는 중괄호를 사용하지 않습니다.
그룹 수준 관련성 보기 / 편집
샘플 인구 조사 설문조사입니다. 첫 번째 페이지에서는 함께 사는 사람이 몇 명인지 묻고 그 값을 "cohabs" 변수에 저장합니다. 이 페이지는 동거인이 한 명보다 많은 경우에만 표시되며(따라서 두 번째 동거인에 대해 표시됩니다), 첫 번째 사람이 본인과 어떤 관계인지(p1_rel)를 지정한 경우에만 표시됩니다.
보시다시피 그룹에는 질문 수준 관련성 기준도 있어서, 각 질문은 바로 앞 질문에 답변한 후에만 표시됩니다(예: {!is_empty(p1_sex)}). EM은 그룹 수준 관련성과 질문 수준 관련성을 자동으로 결합합니다. 그룹 내 질문은 그룹 전체가 관련성이 있는 경우에만 표시됩니다. 그런 다음 그룹 내에서 관련성이 있는 질문의 일부만 표시됩니다.
다음은 해당 질문의 그룹 수준 관련성을 편집하는 화면입니다.
관련성 수식을 입력할 때는 중괄호를 사용하지 않습니다.
맞춤화/파이핑
EM을 사용하면 질문에 대한 단순하거나 복잡한 조건부 맞춤화를 쉽게 수행할 수 있습니다. 때로는 "[제품]을(를) 구매하셨다고 하셨습니다. 어떤 점이 가장 마음에 드셨나요?"처럼 단순한 대체만 필요합니다. 때로는 "[Mr./Mrs.] [LastName]님, 저희 설문조사에 참여해 주시겠습니까?"와 같은 조건부 대체가 필요합니다. 이 경우 응답자의 성별에 따라 Mr. 또는 Mrs.를 사용하려고 합니다. 또 어떤 경우에는 (수학적 계산에 기반한 대체처럼) 훨씬 더 복잡한 대체가 필요합니다. EM은 이러한 모든 유형의 맞춤화/파이핑을 지원합니다.
조건부 수식
체질량지수 예제는 응답자가 미터법 또는 비미터법 단위로 키와 몸무게를 입력하도록 하면서도 BMI를 계산할 수 있음을 보여 줍니다.
여기서 weight_kg는 {if(weight_units == 'kg', weight, weight * .453592)}입니다. 이 if() 함수는 참여자가 킬로그램 단위로 체중을 입력한 경우 그 값을 그대로 사용하고, 그렇지 않으면 입력한 값(파운드 단위)에 .453592를 곱해 킬로그램으로 변환한다는 의미입니다. height_m 변수도 비슷한 방식으로 키를 미터 단위로 계산하며, 인치로 키를 입력한 경우에도 마찬가지입니다.
BMI는 체중 공식을 {weight_kg / (height_m * height_m)}으로 계산합니다.
마지막으로, 보고서는 참여자가 입력한 내용을 알려 주도록 메시지를 조건부로 맞춤 구성합니다. ("키가 2미터이고 몸무게가 70kg이라고 답하셨습니다.")
위 이미지에는 잘 나타나지 않지만, weight_status는 중첩된 if() 문을 사용하여 저체중부터 고도비만까지 분류합니다. 해당 수식은 논리 보기 표시에서 확인할 수 있습니다.
이 질문의 편집 창에서 두 가지를 확인할 수 있습니다:
- 맞춤 구성에서는 표현식을 중괄호로 감싸야 합니다.
- 이 예시처럼 중첩된 조건 논리를 읽기 쉽게 만들고 싶다면 표현식을 여러 줄에 걸쳐 작성할 수 있습니다.
맞춤 구성된 질문, 응답 및 보고서
이 예시는 BMI 보고서를 보여 줍니다.
다음은 같은 질문의 편집 창입니다.
보시다시피 중괄호 안의 모든 내용은 표현식으로 처리되므로 앞의 이미지에서 구문 강조(색상 구분)가 적용되어 있습니다. 변수나 함수 이름의 철자가 틀렸거나 정의되지 않은 경우처럼 오타가 있으면 EM은 오류를 표시합니다. 예를 들어 height_unit은 정의되지 않은 변수 이름(실제 이름은 height_units)이고, rnd()는 정의되지 않은 함수(올바른 함수 이름은 round())임을 보여 줍니다. 두 경우 모두 오류가 빨간 상자로 둘러싸여 있어 쉽게 찾아 수정할 수 있습니다.
또한 입력한 값의 표나 맞춤 조언과 같은 복잡한 보고서도 빠르게 만들 수 있습니다.
LimeSurvey가 질문에서 어느 부분이 자유 텍스트이고 어느 부분을 Expression Manager로 처리해야 하는지 알 수 있도록, 모든 맞춤 구성에서는 표현식을 반드시 중괄호로 감싸야 한다는 점을 기억하십시오.
유효성 검사
EM은 대부분의 고급 질문 옵션이 작동하는 방식을 제어합니다. 이 옵션들은 최소/최대 응답 수, 개별 값의 최소/최대, 합계의 최소/최대, 입력한 값이 지정한 문자열 패턴과 일치하는지 확인하는 것 등을 제어합니다. 이러한 고급 질문 옵션은 지금까지처럼 입력하시면 됩니다. 다만 이제 해당 필드의 모든 값은 표현식으로 간주되므로, 다른 질문과 복잡한 조건 관계를 가진 최소/최대 기준을 설정할 수 있습니다.
이 모든 경우에 고급 질문 옵션은 항상 표현식으로 간주되므로 지정할 때 중괄호를 사용하지 않습니다.
샘플 설문조사 페이지에서 유효성 검사에 표현식을 사용하는 다양한 실제 예시를 확인할 수 있습니다.
소개
LimeSurvey는 새로운 Expression Manager(EM) 모듈을 사용하여 더 복잡한 분기, 평가, 유효성 검사 및 맞춤 구성을 지원합니다. EM은 LimeSurvey가 백엔드에서 대체 필드, 조건 및 평가를 관리하는 방식을 대체합니다. 또한 실행 시 데이터베이스 읽기를 대부분 없애므로 처리 속도도 크게 향상됩니다. EM은 Thomas White 박사(TMSWhite)가 개발했습니다.
이 위키 페이지는 Expression Manager의 구문과 기능에 대한 공식 참조 문서입니다.
주요 정의
- 표현식: 중괄호로 둘러싸인 모든 내용
- 여는 중괄호 바로 뒤나 닫는 중괄호 바로 앞에 공백이 없어야 합니다.
- 표현식의 내용은 EM이 평가하므로 수식, 함수, 복잡한 문자열 및 날짜 처리를 포함할 수 있습니다.
- 맞춤 구성(Tailoring): "파이핑"이라고도 하며, 텍스트를 조건에 따라 수정하는 과정입니다.
- 모든 '대체 필드', 참가자 데이터 및 답변 데이터에 접근할 수 있습니다.
- 질문, 응답 및 해당 속성에도 더 쉽게 접근할 수 있습니다.
- 관련성 수식: 질문의 표시 여부를 제어하는 새로운 질문 속성
- 관련성 수식이 있으면 그 결과가 참일 때만 질문이 표시됩니다.
- 내부적으로 모든 array_filter 및 array_filter_exclude 명령은 하위 질문 수준의 관련성이 됩니다.
- 수식 질문 유형: 계산 결과나 보고서를 데이터베이스에 저장하는 새로운 질문 유형
- Boilerplate 질문과 비슷하지만, "이 질문 항상 숨기기"를 설정하더라도 그 내용이 데이터베이스에 저장됩니다.
- 질문 코드: EM에서 선호하는 변수 이름
- 질문의 목적을 나타내는 설명적인 이름을 사용할 수 있어 복잡한 논리를 읽기 쉽게 해 줍니다.
- 유효한 질문 코드는 숫자로 시작해서는 안 되므로, 질문 코드로 질문에 번호를 매길 때는 "q1", "q1a" 또는 "g1q2"와 같이 사용하십시오.
- SPSS나 R로 자료를 내보낼 때 현재 변수 이름이 되는 값이므로, 통계 분석을 하신다면 이미 고유하게 지정하셨을 것입니다.
EM을 꼭 사용해야 하나요?
간단히 답하면 아니요입니다(하지만 어느 면에서는 예이기도 합니다).
EM은 기존 설문조사와 완전한 하위 호환성을 제공합니다. 따라서 LimeSurvey 1.91+ 이하 버전에서 사용하던 방식의 조건과 평가를 계속 사용하셔도 됩니다.
그러나 EM은 LimeSurvey가 내부적으로 조건을 처리하는 방식을 완전히 대체합니다. 조건 편집기를 사용하여 조건을 생성하고 관리할 수는 있지만, LimeSurvey 1.92는 이를 동등한 관련성 수식으로 변환합니다. 업그레이드 과정에서 LimeSurvey 1.92는 기존의 모든 조건을 관련성 수식으로 자동 변환합니다.
이를 통해 두 방식의 장점을 모두 누릴 수 있습니다. 기존에 익숙한 방식으로 LimeSurvey를 계속 사용하면서 동등한 관련성 수식을 확인할 수 있으므로, 적절하다고 판단될 때 점진적으로 관련성 수식을 직접 사용하는 방식으로 전환할 수 있습니다.
조건과 관련성을 함께 사용할 수 있나요?
예. 일부 질문에는 조건 편집기를, 다른 질문에는 관련성 편집기를 사용할 수 있습니다. 조건은 질문을 저장할 때 관련성으로 자동 변환됩니다.
조건 편집기를 사용하는 경우, 해당 조건이 직접 입력한 관련성 수식을 덮어쓰기를 원하는 것으로 간주합니다. 따라서 기존 조건이 있는 상태에서 관련성을 직접 편집하려면 먼저 해당 질문의 조건을 삭제하십시오. 구체적으로는 생성된 관련성 수식을 텍스트 편집기에 복사하고, 조건 메뉴에서 해당 질문의 모든 조건을 삭제한 다음(관련성도 함께 삭제됩니다), 질문을 편집하여 텍스트 편집기에 있던 관련성 수식을 해당 질문의 관련성 필드에 다시 붙여넣고 질문을 저장하십시오. 생성된 관련성 수식을 삭제하지 않고 조건만 삭제하는 기능에 대한 요구가 충분히 많다면, 일괄 변환 기능을 추가할 수도 있습니다.
조건과 관련성 중 무엇을 선택해야 하나요?
각 방식의 장단점은 다음과 같습니다:
| 방식 | 장점 | 단점 |
|---|---|---|
| 조건 | 1. 간단한 조건을 만들기 위한 편리한 GUI 2. 지원팀이 GUI를 잘 이해하고 있으며 문서화가 잘 되어 있음 |
1. 단순한 비교만 지원하며 AND/OR 조건을 잘 처리하지 못함 2. 연쇄 조건이 불규칙하게 동작함 3. 느림 - 데이터베이스를 많이 사용하므로 긴 설문조사가 느려질 수 있음 4. 조건을 다시 불러올 때 문제가 보고된 적이 있음 5. 질문이 수십, 수백, 수천 개일 때 GUI가 확장성이 떨어짐 6. SGQA 이름을 사용해야 하므로 종이 설문조사를 변환하는 데 시간이 오래 걸릴 수 있음 7. 복잡한 분기에 필요한 로직은 프로그래머가 직접 코딩해야 하는 경우가 많음 |
| 관련성 | 1. 80개 이상의 함수와 수학/문자열 연산자를 포함한 매우 복잡한 로직을 지원함 2. 연쇄 로직을 완벽하게 지원함 3. 빠름 - 추가 데이터베이스 호출이 없어 1000개 이상의 질문이 있는 설문조사도 지원함 4. SGQA 코드가 필요하지 않으므로 로직을 다시 불러올 때 문제가 없음 5. 구문 강조가 1000개 이상의 질문이 있는 설문조사에서도 잘 동작함 6. 기존 종이 설문조사를 전산화하려는 그룹이 쉽고 빠르게 사용할 수 있음 7. 프로그래머 없이도 반구조화 인터뷰와 역학 설문조사를 손쉽게 지원함 |
1. 간단한 조건을 위한 GUI가 없음 - 대신 구문 강조를 사용함 2. 새로운 기능이므로 지원팀이 아직 EM에 숙달되지 않았음 |
결론적으로, LimeSurvey 1.91+의 동작 방식에 만족하신다면 지금 사용하는 방식을 바꿀 이유는 없습니다.
EM을 사용하면 또 어떤 이점이 있나요?
다음은 EM을 사용하고 싶어질 수 있는 다른 이유들입니다.
- 계산 - 생각할 수 있는 모든 계산을 만들 수 있습니다:
- 일반적인 모든 수학 연산자와 함수를 사용할 수 있습니다
- 70개 이상의 수학, 날짜, 문자열 처리 함수를 사용할 수 있습니다
- 사용자가 필요로 하면 개발자가 새 함수를 비교적 쉽게 추가할 수 있습니다
- 계산 결과를 데이터베이스에 저장
- 이제 JavaScript 없이도 단순하거나 복잡한 계산 및/또는 척도 점수를 계산하고 데이터베이스에 저장할 수 있습니다.
- 이를 위해 수식 질문 유형을 사용합니다.
- 평가
- 이제 이전에 지원되던 일부 유형만이 아니라 모든 질문 유형에서 평가나 척도 점수를 만들 수 있습니다
- 필요한 곳 어디에서나(같은 페이지에서도) 테일러링을 사용하여 누적 또는 합계 평가 점수를 표시할 수 있습니다
- 이러한 평가 점수를 기반으로 생성되는 보고서를 더 세밀하게 제어할 수 있습니다
- JavaScript 없이도 평가 점수를 데이터베이스에 저장할 수 있습니다
- JavaScript나 CSS 없이도 평가 점수를 숨길 수 있습니다
- 대체 필드
- 질문 코드를 사용하여 이전 질문의 응답 값을 삽입할 수 있으며, 이렇게 하면 읽고 검증하기가 더 쉬워집니다.
- 테일러링 - 다른 값에 따라 조건부로 텍스트를 표시할 수 있습니다
- 응답자에게 알맞은 호칭을 사용할 수 있습니다(예: "안녕하세요 [Mr./Mrs.] Smith")
- 단수/복수가 중요한 경우 문법적으로 올바른 문장을 출력할 수 있습니다(예: "자녀가 1명 있습니다" 대 "자녀가 2명 있습니다")
- 응답자의 성별과 수에 따라 동사를 적절히 활용하고 명사를 적절히 변화시킬 수 있습니다.
- 새로운 변수 속성 - 테일러링을 위해 다음 속성에 접근할 수 있습니다:
- (접미사 없음) - qcode.code의 별칭
- .code - 질문이 관련성이 있는 경우 해당 질문에서 선택된 답변 코드(그렇지 않으면 빈 값), 코드가 있는 질문이 아닌 경우 텍스트 값
- .NAOK - .code와 같지만 관련성이 없는 경우에도 계산이나 목록에 포함될 수 있음
- .value - 질문이 관련성이 있는 경우 해당 질문의 평가 가치(그렇지 않으면 빈 값), 코드가 있는 질문이 아닌 경우 텍스트 값 -- 설문조사에서 평가가 활성화된 경우에만 사용할 수 있으며, 그렇지 않으면 항상 0
- .valueNAOK - .value와 같지만 관련성이 없는 경우에도 계산이나 목록에 포함될 수 있음
- .shown - 사용자에게 표시된 응답
- .qid - 질문 ID
- .gid - 그룹 ID
- .sgqa - 질문의 SGQA 값
- .jsName - 이 페이지 또는 다른 페이지에 정의되었는지와 관계없이 해당 질문에 대한 올바른 JavaScript 변수 이름
- .qseq - 질문 순서(0부터 시작)
- .gseq - 그룹 순서(0부터 시작)
- .mandatory - 질문의 필수 여부(Y/N)
- .question - 질문 텍스트
- .relevance - 질문의 관련성 수식
- .grelevance - 그룹의 관련성 수식
- .relevanceStatus - 질문이 현재 관련성이 있는지 여부(불리언, PHP와 JS에서 다를 수 있음)
- .type - 질문 유형(한 글자 코드)
- 페이지 내 동적 변경
- 모든 관련성, 계산, 테일러링이 페이지에서 동적으로 작동하므로 값이 바뀌면 페이지가 즉시 업데이트됩니다
- 따라서 질문이 관련성이 있는지 여부에 따라 동적으로 나타나거나 사라지게 할 수 있습니다
- 질문도 페이지의 답변에 따라 동적으로 테일러링되므로, 누적 합계, 맞춤 문장, 맞춤형 보고서를 볼 수 있습니다.
- 새로운 자료 입력 화면
- 기존 데이터 입력 시스템 외에도 Survey-All-In-One을 사용할 수 있습니다.
- 이는 페이지 내 관련성과 테일러링을 지원하므로, 데이터 입력 담당자가 탭 키로 빠르게 이동하면서 관련성이 있는 답변만 입력하면 됩니다
- 데이터 입력 담당자가 마찬가지로 동적으로 작동하는 테일러링을 확인해야 하는 경우에 매우 중요할 수 있습니다.
- 대부분의 사용자 지정 JavaScript가 필요 없음
- EM은 복잡한 계산, 점수 산정, 테일러링, 조건부 로직을 손쉽게 지원합니다.
- 사용자 지정 레이아웃이나 질문 하위 요소의 조건부 숨김 같은 일부 작업에는 여전히 JavaScript가 필요하지만, JavaScript에서 EM 함수를 사용하면 SGQA 대신 Qcode로 질문에 접근하고 위에 나열된 모든 질문 속성에 접근할 수 있습니다.
EM으로 사용할 수 있는 다른 유용한 새 기능에는 무엇이 있나요?
조건 편집기를 계속 사용하든 관련성 수식을 직접 작성하든, 다음과 같은 추가 이점을 얻을 수 있습니다:
- 더 복잡한 유효성 검사 기준을 만들 수 있습니다.
- max_answers, min_num_value_n, max_num_value와 같은 모든 고급 질문 속성에서 표현식을 사용할 수 있습니다. 따라서 같은 페이지에 있는 이전 답변이라도 그 답변을 기반으로 최소/최대 기준을 쉽게 조정할 수 있습니다.
- EM은 정규식 기반 유효성 검사도 모두 처리하므로 preg와 수식 기반 질문 속성을 안정적으로 함께 사용할 수 있습니다.
- 질문과 그룹을 쉽게 재정렬(또는 삭제)할 수 있습니다.
- 1.92 버전 이전에는 재정렬로 인해 해당 질문이나 그룹이 사용된 조건이 깨질 수 있다고 LimeSurvey가 판단하면 질문이나 그룹을 재정렬할 수 없었습니다. 마찬가지로 다른 질문이 의존하는 질문은 삭제할 수 없었습니다.
- EM의 구문 강조를 사용하면 질문이 선언되기 전에 사용했는지 쉽게 확인하고 검증할 수 있습니다. 그래서 이제는 언제든지 질문과 그룹을 재정렬하거나 삭제할 수 있습니다. EM이 모든 구문 강조를 업데이트하여 잠재적인 오류를 보여 줍니다.
- 질문 재정렬 보기가 이러한 검토에 도움이 되도록 개선되었습니다. 이제 질문의 관련성 수식과 맞춤화가 표시되므로, 변수가 분홍색으로 표시되는지(선언되기 전에 사용되었다는 의미) 바로 확인할 수 있습니다.
- 질문/그룹 탐색 인덱스를 항상 사용할 수 있으며 정확합니다.
- 1.92 버전 이전에는 복잡한 조건이 있으면 이러한 인덱스를 사용할 수 없었습니다.
- EM을 사용하면 인덱스가 정확하다고 보장할 수 있습니다.
- 응답자는 이전 질문으로 돌아가 응답을 변경한 다음 다시 앞으로 이동(또는 제출)할 수도 있습니다.
- 앞으로 이동할 때 EM은 그 사이에 있는 모든 질문/그룹을 다시 검증합니다.
- 관련성이 없어진 질문은 데이터베이스에서 NULL 처리되므로 데이터의 내부 일관성이 유지됩니다.
- 관련성이 생겼거나 필수 또는 유효성 검사 규칙을 새로 충족하지 못하는 질문이 있으면, EM은 해당 페이지에서 멈추고 최종 목적지로 이동하기 전에 사용자가 그 질문에 응답하도록 합니다.
- 조건을 관련성으로 자동 변환합니다.
- 데이터베이스를 업그레이드하면 조건이 있는 모든 기존 설문조사에 대해 관련성 수식이 생성됩니다.
- 설문조사를 가져올 때마다 필요에 따라 관련성 수식이 생성됩니다.
- 조건을 추가, 삭제 또는 수정할 때마다 EM이 적절한 관련성 수식을 생성합니다.
- 편리한 구문 강조
- EM은 관련성 수식을 표시할 때 SGQA 코드를 입력했더라도 Qcode를 표시합니다. 그 편이 읽기 더 쉽다고 보기 때문입니다.
- 모든 변수는 현재 질문(또는 현재 그룹)보다 앞에서 선언되었는지 뒤에서 선언되었는지를 색상으로 구분해 표시합니다. 이를 통해 관련성(array_filter 포함), 맞춤화 또는 유효성 검사 수식에서 변수를 선언하기 전에 사용하는 경우를 빠르게 찾아 수정할 수 있습니다.
- 또한 색상으로 구분된 변수 위에 마우스를 올리면 해당 질문의 가장 중요한 메타데이터가 표시됩니다. 여기에는 그룹 순번, 질문 순번, Qcode, 질문 텍스트, 그리고 (열거된 응답 선택지가 있는 질문 유형인 경우) 사용 가능한 모든 응답 선택지가 포함됩니다.
- 응답 선택지 목록은 다음 구문을 사용합니다: 'answers':{key:val, ... }.
- key의 구문은 'scale~code'이며, 여기서 scale은 응답 척도(예: 이중 척도), code는 응답 코드입니다.
- val의 구문은 'value~shown'이며, 여기서 value는 평가 값(평가를 사용하는 경우, 그렇지 않으면 code)(예: Qcode.value), shown은 응답자에게 보이는 표시 값(예: Qcode.shown)입니다.
- 따라서 많은 설문조사에서 평가 모드 없이도 계산을 사용할 수 있습니다. 열거된 응답 옵션이 고유하고 소수가 아니며 음수가 아니라면 Qcode.code 값으로 간단히 계산할 수 있습니다.
- 전체 설문조사 로직과 내용을 쉽게 검토할 수 있습니다.
- 새로운 설문조사 로직 보기 기능을 통해 설문조사(또는 그룹이나 질문)의 모든 내용을 한 페이지에서 볼 수 있습니다.
- 선택한 범위(설문조사, 그룹 또는 질문)에 대해 그룹, 질문, 하위 질문, 응답 수준의 세부 정보를 보여 줍니다.
- 또한 관련성, (array_filter 및 array_filter_exclude용) 하위 질문 수준 관련성, (preg 및 값의 최소/최대 합계/개수와 같은 유효성 검사 규칙용) 생성된 유효성 검사 수식, 그리고 비어 있지 않은 모든 질문 속성을 표시합니다.
- 모든 내용이 구문 강조되므로 괄호 불균형이나 선언 전 변수 사용과 같은 잠재적인 구문 오류를 확인할 수 있습니다.
- 구문 강조를 통해 설문조사를 빠르게 탐색하고 편집할 수 있습니다.
- 변수 이름을 클릭하면 브라우저 창(또는 탭)이 열리고 해당 질문을 보고 편집할 수 있습니다.
- 그룹 이름을 클릭하면 브라우저 창(또는 탭)이 열리고 그룹 재정렬 보기가 표시되어 질문을 쉽게 이동할 수 있습니다.
- 모든 질문 속성도 구문 강조됩니다. 따라서 고급 질문 옵션 안에서 표현식을 설정하고 확인할 수 있습니다(예: 값의 최대/최소 개수/합계를 표현식 기반으로 지정).
- EM 개발자는 유사한 보기(조금 더 깔끔한 형태)를 사용하여, 함께 일하는 역학자와 기관생명윤리위원회가 수천 개의 질문으로 이루어진 고도로 분기되고 맞춤화된 구조화 인터뷰 설문조사를 검증하고 승인하도록 했습니다.
시작하기
EM을 시작하는 가장 좋은 방법은 다음과 같습니다:
- http://www.limesurvey.org/en/download 에서 최신 안정 버전을 설치합니다.
- 샘플 설문조사를 가져와서 살펴봅니다.
- 사용 사례 및 방법 안내와 단계별 예제를 살펴봅니다.
- EM 문서(이 페이지)를 살펴봅니다.
- 내장된 EM 테스트 모음을 확인합니다.
- 아무 설문조사에서나 도구 아래의 EM 옵션을 선택합니다.
- 사용 가능한 함수에는 70개 이상의 함수와 구문이 나열되어 있습니다.
- 개별 표현식의 단위 테스트
- 모든 EM 함수와 연산자를 사용하는 예제와 PHP 및 JavaScript 결과를 보여 줍니다.
- PHP와 JavaScript 버전에서 결과가 다르게 나오는 함수가 몇 개 있으므로, 이 페이지를 통해 EM 로직을 그에 맞게 계획할 수 있습니다.
Expression Manager는 어떤 기능을 확장/대체합니까? (LimeSurvey <= 1.91+)
조건 => 관련성
조건은 어떤 질문을 표시할지 제어했습니다. 일반적인 구문은 SGQA 연산자 값이었으며, 예를 들면 111X2X3 == "Y"와 같습니다. 조건은 AND 또는 OR로 결합할 수 있었지만 AND와 OR를 섞어서 사용하기는 어려웠습니다. 조건 자체는 별도의 테이블에 저장되었고, LimeSurvey 코드의 상당 부분이 조건을 관리하는 데 사용되었습니다. 데이터베이스 접근이 많았기 때문에 많은 수의 조건을 처리하면 눈에 띄는 성능 문제가 발생할 수 있었습니다. 게다가 질문이나 그룹에 조건이 지정되면 질문이나 그룹을 재정렬하거나 삭제할 수 없는 경우가 많았습니다.
평가 => 수식 및 마이크로 맞춤화
평가를 통해 사용자는 여러 질문을 모아 척도 점수를 만들 수 있었습니다. 그러나 현재 페이지에서 동적으로 변경될 수 없었고, 그 값이 데이터베이스에 저장되지도 않았습니다.
대체 => 마이크로 맞춤화
사용자는 이전 답변을 기반으로 일부 메시지와 질문을 맞춤화할 수 있었습니다. 예를 들어 질문을 {TOKEN:FIRSTNAME}, you said {SPORT.shown} was your favorite sport와 같이 만들 수 있었습니다. 그러나 응답자의 성별에 따라 "Mr." 또는 "Mrs."를 표시하는 것과 같은 조건부 맞춤화나, 동사 활용 및 명사 곡용은 복잡한 JavaScript 없이는 불가능했습니다. 작성자가 질문을 맞춤화하는 것처럼 보이는 설문조사를 구현할 수는 있었지만, 경우의 수마다 별도의 질문이 필요했고 어떤 질문을 표시할지 결정하기 위한 복잡한 조건도 필요했습니다.
유효성 검사
질문은 정규식이나 최소/최대 값으로 검증하거나, 한 답변을 최소값 또는 최대값으로 사용하도록 할 수 있었습니다. 그러나 복잡한 JavaScript 없이는 다른 변수의 계산 결과를 기반으로 유효성 검사를 수행할 수 없었습니다.
수식
복잡한 JavaScript 없이는 수식이 지원되지 않았습니다.
수식 질문 유형
복잡한 JavaScript 없이는 수식(예: 평가의 최종 점수)을 데이터베이스에 저장할 수 없었습니다.
Expression Manager는 어떻게 그 기능을 대체/확장합니까?
Expression Manager는 LimeSurvey의 새로운 핵심 모듈로, 이전에는 사용자 지정 JavaScript가 필요했던 복잡한 기능을 훨씬 쉽게 지원합니다. 또한 LimeSurvey가 현재 조건과 평가를 관리하는 방식을 대체하고 있습니다.
Expression Manager(EM) 관련 새 용어
EM은 자신의 기능을 다음과 같은 용어로 "생각"합니다:
- 관련성 기반 분기 - 질문이 관련성이 있으면 질문하고, 그렇지 않으면 질문하지 않습니다(예: 보이지 않게 하고 데이터베이스에 NULL로 표시). 모든 질문 유형과 각 그룹에 새로운 관련성 필드가 있습니다(따라서 각 질문에 같은 조건을 복사하지 않고도 전체 그룹에 조건 집합을 적용하거나, 그룹 수준과 질문 수준의 조건부 로직을 결합할 수 있습니다).
- 맞춤화 - 어떤 질문을 해야 하는지 알고 나면, 맞춤화(파이핑이라고도 함)가 질문을 어떻게 할지를 지정합니다. 이를 통해 단순한 대체(예: {TOKEN:FIRSTNAME})뿐만 아니라 응답자의 성별이나 수에 따른 동사 활용과 명사 곡용도 지원할 수 있습니다. 또한 다른 질문에 응답했는지(또는 어떻게 응답했는지)에 따라 응답자에게 전달하는 메시지를 바꿀 수 있습니다.
- 수식 - EM은 표현식의 결과를 저장하는 수식이라는 새로운 질문 유형을 추가합니다. 이 수식 결과는 페이지에서 숨기더라도 계산되어 데이터베이스에 기록됩니다. 따라서 숨겨진 점수 계산, 복잡한 수식에 기반한 탐색, 평가, 그리고 데이터베이스 내에서 생성되어 쉽게 사용할 수 있어야 하는 보고서에 유용합니다.
관련성 및 연쇄 관련성
이제 모든 질문 유형에 질문 표시 여부를 제어하는 관련성 옵션이 있습니다. EM은 설문조사에 나타나야 하는 순서대로 각 관련성 수식을 처리합니다. 표현식이 참이면(또는 이전 설문조사를 지원하기 위해 비어 있으면) 질문이 표시됩니다. 관련성이 없으면 질문이 숨겨지고 데이터베이스에서 값이 NULL 처리됩니다. 그룹에 관련성이 있는 질문이 없으면 그룹 전체를 건너뜁니다.
또한 표현식 안의 변수 중 하나라도 관련성이 없으면 표현식은 항상 거짓으로 평가됩니다. 이를 통해 연쇄 관련성이 가능해지므로 각 질문에 매우 긴 관련성 수식을 작성할 필요가 없습니다.
질문이 Q1-Q5까지 5개 있고, Q1에 응답한 경우에만 Q2를 표시하고 Q2에 응답한 경우에만 Q3를 표시하는 식으로 하려고 한다고 가정해 보겠습니다. 관련성 수식은 다음과 같을 수 있습니다:
| 질문 코드 | 관련성 | 질문 |
|---|---|---|
| Q1 | 1 | 이름이 무엇입니까? |
| Q2 | Q1 | {Q1}님, 나이가 어떻게 되십니까? |
| Q3 | Q2 | {Q2}세이시군요. 결혼하셨습니까? |
| Q4 | Q3 == "Y" | {Q1}님, 결혼하신 지 얼마나 되었습니까? |
| Q5 | Q4 | {Q1}님, 자녀는 몇 명입니까? |
관련성 계산은 JavaScript에서도 작동하므로 위의 질문을 모두 한 페이지에 넣어도 예상대로 작동합니다. 사실 EM은 설문조사 전체 표시, 그룹별 표시, 질문별 표시 형식을 처리하는 방식을 완전히 대체합니다. 이제 모두 동일한 탐색 엔진을 사용하므로 설문조사 스타일에 관계없이 똑같이 작동합니다.
같은 페이지에 있는 동안에는 입력한 데이터가 숨겨진 채로 그대로 남아 있습니다. 따라서 정보를 입력한 다음 관련성이 없어지는 옵션을 선택했다가 다시 관련성이 있도록 만들면 이전 답변을 그대로 사용할 수 있습니다. 그러나 다른 페이지로 이동하는 순간 관련성이 없는 모든 답변은 데이터 세트의 무결성을 위해 삭제됩니다.
그룹 수준 관련성
Expression Manager는 그룹 수준 관련성도 지원합니다. 이를 통해 반복(루프) 처리를 더 쉽게 구현할 수 있습니다. 예를 들어 최대 10개의 대상(제품이나 가구 구성원 등)에 대한 정보를 수집한다고 가정해 보겠습니다. 먼저 후속 질문이 필요한 대상의 수를 파악합니다(예: 가구에 몇 명이 사는지 묻거나, 긴 목록에서 좋아하는 제품을 선택하도록 하는 방식). 후속 질문이 필요한 대상의 수를 알게 되면, 10개의 후속 질문 그룹 각각에 {count >= 1}, {count >=2}, ... {count >= 10}과 같은 그룹 수준 관련성을 사용할 수 있습니다. 각 그룹 안에서는 질문 수준의 조건부 논리를 사용할 수 있습니다(예: 각 대상의 성별이나 연령에 따른 후속 질문). 질문 수준과 그룹 수준의 관련성 수식은 AND로 결합되어 표시 여부를 결정합니다.
맞춤화 / 파이핑
중괄호 안의 모든 내용은 이제 표현식으로 처리됩니다(아래에 설명된 한 가지 예외 제외). 표현식은 모든 LimeReplacementFields, 모든 변수(여러 별칭을 통해), 모든 일반적인 수식 연산자(수학, 논리, 비교), 그리고 수십 개의 함수(클라이언트 측에서도 동적으로 작동)에 접근할 수 있습니다.
이러한 수식을 사용하여 다음과 같은 작업을 할 수 있습니다:
- 이전 답변에 따라 응답자에게 맞춤형 메시지를 조건부로 표시
- 평가 모듈 자체를 사용하지 않고 평가를 생성하고 그 결과를 표시(또는 그 결과에 따라 조건부로 분기하거나 메시지 표시)
- 질문, 응답, 보고서 내에서 동사를 활용하고 명사를 변형
- 설문조사 마지막의 "답변 표시" 페이지 전에 답변 요약 표시
수식
수식이라는 새로운 질문 유형이 있습니다. 이 유형은 Boilerplate 질문과 비슷하지만, 표시되는 내용의 값을 데이터베이스에 저장한다는 점이 다릅니다. 따라서 수식 질문 텍스트에 평가 계산이 포함되어 있으면, 그 값이 공개 또는 비공개 통계에 표시할 수 있는 변수로 데이터베이스에 저장됩니다.
이를 통해 평가 점수를 데이터베이스에 저장하고 싶다는 흔한 요청이 해결됩니다.
구문
중괄호 안에 포함된 모든 내용은 이제 표현식으로 간주됩니다(한 가지 예외: 앞이나 뒤에 공백이 없어야 합니다. 이는 Expression Manager가 포함된 JavaScript를 처리하려고 시도하지 않도록 하기 위한 것입니다).
표현식은 여러 줄에 걸쳐 작성해도 되며, 여는 중괄호 뒤나 닫는 중괄호 앞에 공백이 없으면 됩니다. 이는 다음과 같이 중첩된 if() 문에 특히 유용합니다:
{if(is_empty(PFTotals),
'',
if(PFTotals >= -5 && PFTotals <= -4,
'Very Soft',
if(PFTotals >= -3 && PFTotals <= -2,
'Soft',
if(PFTotals == -1,
'Somewhat Soft',
if(PFTotals == 0,
'Moderate',
if(PFTotals == 1,
'Somewhat Hard',
if(PFTotals >= 2 && PFTotals <= 3,
'Hard',
if(PFTotals >= 4 && PFTotals <= 5,
'Very Hard',
''
)
)
)
)
)
)
)
)}
- 모든 표준 수학 연산자 (예: +,-,*,/,!)
- 모든 표준 비교 연산자 (예: <,<=,==,!=,>,>=, 그리고 다음과 같은 동등한 표현: lt,le,eq,ne,gt,ge)
- 괄호 (하위 표현식을 그룹화할 수 있음)
- 조건 연산자 (예: &&,| | 그리고 다음과 같은 동등한 표현: and,or)
- 작은따옴표 및 큰따옴표 문자열 (각각 다른 종류의 따옴표로 된 문자열을 포함할 수 있음)
- 쉼표 연산자 (표현식 목록을 나열하고 마지막 결과만 반환할 수 있음)
- 할당 연산자 (=)
- 사전 정의된 변수 (질문, 질문 속성, 답변을 참조) - 예: 모든 SGQA 코드
- 사전 정의된 함수 (이미 70개 이상 있으며 추가하기 쉬움)
연산자
EM 구문은 일반적인 연산자 우선순위를 따릅니다:
| 수준 | 연산자 | 설명 |
|---|---|---|
| 1 | () | 그룹화 또는 함수 호출을 위한 괄호 |
| 2 | ! - + | 단항 연산자: 부정(not), 음수화, 단항 플러스 |
| 3 | * / | 곱하기, 나누기 |
| 4 | + - | 더하기, 빼기 |
| 5 | < <= > >= lt le gt ge | 상대 비교 |
| 6 | == != eq ne | 동등 비교 |
| 7 | and | 논리 AND |
| 8 | or | 논리 OR |
| 9 | = | 할당 연산자 |
| 10 | , | 쉼표 연산자 |
더하기 연산자(+) 관련 주의사항
JavaScript와 PHP 간의 일관성을 위해, 더하기 연산자(+)는 두 피연산자가 모두 숫자이면 덧셈을 수행하고, 두 피연산자가 모두 숫자가 아닌 문자열이면 연결을 수행합니다. 그러나 연결에는 join() 함수를, 덧셈에는 sum() 함수를 사용할 것을 권장합니다. 그렇게 하면 의도가 더 명확해지고, 문자열을 예상했는데 숫자가 나오는 경우(또는 그 반대)에 발생하는 예기치 않은 결과를 피할 수 있습니다.
숫자와 문자열 불일치 및 알파벳 순서 비교 관련 주의사항
상대 비교나 동등 비교로 값을 비교할 때는 유형 불일치에 주의하십시오. 사용자가 입력한 값이나 선택한 응답 코드는 명확히 숫자인 경우 숫자로 사용될 수 있습니다.
값 중 하나를 "로 둘러싸면 텍스트(알파벳 순서) 비교로 강제됩니다. 숫자로 비교하려면 숫자를 절대 따옴표 "로 둘러싸지 마십시오.
예를 들어 Q0.NAOK가 값이 9인 숫자 질문일 때 Q0.NAOK > "50"은 참입니다. 이는 연산자 >가 숫자 비교가 아닌 알파벳 순서 비교로 간주하기 때문입니다.
정수 값을 확실하게 비교하려면 intval(Q0.NAOK) > 50을 사용할 수 있습니다. 단, Q0.NAOK가 숫자가 아니면(비어 있거나 문자열이면) intval(Q0.NAOK) == 0이 된다는 점을 기억하십시오. 문자열 값("A" < "B")을 비교하려면 strcmp를 직접 사용하십시오: strcmp(Q0.NAOK,"B") 또는 strcmp(Q0.NAOK,"A5").
할당 연산자(=) 사용 시 주의사항
할당 연산자는 예기치 않은 부작용을 일으킬 수 있으므로 꼭 필요한 경우가 아니면 사용하지 않는 것이 좋습니다. 예를 들어 이전 답변의 값을 변경하면, 해당 질문과 현재 질문 사이의 연쇄 관련성 및 유효성 검사 논리가 다시 계산되지 않으므로, 내부적으로 일관성 없는 데이터가 생길 수 있습니다(예: 응답이 유지되지만 NULL 처리되어야 하는 질문, 또는 건너뛰었지만 응답되어야 하는 질문). 일반적으로 변수에 값을 할당하려면 수식 질문 유형을 생성하고 표현식을 사용하여 값을 설정해야 합니다. 그러나 이 연산자가 정말 필요한 드문 경우도 있어 사용할 수 있도록 제공하고 있습니다.
이 연산자에 대해 주의를 환기하기 위해, 구문 수식 안에서 빨간색 글꼴로 표시됩니다("=="와 혼동하지 않도록 하기 위함입니다).
할당 연산자 사용
할당을 사용하고 싶은 주된 이유는 다음과 같습니다:
- 수식을 통한 기본값을 허용하지 않는 질문의 기본값을 설정해야 하는 경우(예: 사용자 인터페이스에서 응답 옵션 중 하나를 선택할 수는 있지만 수식을 입력할 수는 없는 라디오 목록). 단, LimeSurvey는 수식이 해당 질문에 허용되는 응답 중 하나를 생성하는지 검증할 수 없으므로 주의하십시오.
- 이후의 답변에 따라 이전 질문의 답변을 강제로 변경해야 하는 경우
- 복잡한 할당량이 필요한 경우: 할당량용으로 숨겨진 단일 선택 질문 하나를 사용하고 할당을 통해 값을 설정
- 기타 등등...
이 목적을 위해 Expression Manager의 모든 기능을 사용할 수 있습니다.
몇 가지 예시:
- 짧은 텍스트 질문의 응답을 소문자로 설정:
{QCODE=strtolower(QCODE.NAOK)} - 설문조사 시작 시 배열 질문 유형의 기본 응답 설정:
{Q1_SQ1=((is_empty(Q1_SQ1.NAOK),"A99",Q1_SQ1.NAOK)} - 설문조사 시작 시 배열 텍스트 질문 유형의 기본 응답 설정:
{Q1_SQY1_SQX1 = ((is_empty(Q1_SQY1_SQX1.NAOK),"Inserted answer", Q1_SQY1_SQX1.NAOK)} - 조건에 따라 응답 설정:
{QCODE=if(YesNo="Y","A1","")}
XSS 보안
XSS가 활성화된 경우 일부 Expression Manager 시스템을 사용할 수 없습니다:
- 한 표현식에서 HTML 태그를 시작하고 다른 표현식에서 종료하는 경우
- URL에 복잡한 표현식을 사용하는 경우
예시 및 해결 방법
{if( 1 ,"<strong>","")}information{if( 1 ,"</strong>","")}는 XSS 보안 하에서 작동하지 않습니다. 이 경우{if(1,"<strong>information</strong>","information")}를 사용할 수 있습니다.<a href="/script.php?value={if(QCODE == "Y","yes","no")}">next</a>의 경우, 전체 질문 코드를 사용하는 것은 허용되므로 수식 질문을 사용할 수 있습니다:<a href="/script.php?value={EQUATION.NAOK}">next</a>
변수 접근
Expression Manager는 필요한 모든 변수에 대한 읽기 전용 접근을 제공합니다. 하위 호환성을 위해 다음 항목에 접근할 수 있습니다:
- TOKEN:xxx - TOKEN의 값 (예: TOKEN:FIRSTNAME, TOKEN:ATTRIBUTE_5) (익명 설문조사가 아닌 경우에만 해당).
- QCODE.shown - Expression Manager를 사용한 응답의 표시 값 (예: "예").
- 템플릿에서 사용하는 {XXX} 값 전체.
- 질문 텍스트에서는 질문 ID로 대체되는 {QID}와 질문의 SGQA로 대체되는 {SGQ}를 사용할 수 있습니다.
또한 Expression Manager에서는 질문 코드(데이터베이스의 질문 테이블에 있는 'title' 열)로 변수를 참조할 수 있습니다. 이는 데이터를 SPSS, R 또는 SAS로 내보낼 때 사용되는 변수 레이블이기도 합니다. 예를 들어 이름, 나이, 성별에 대한 질문이 있다면 해당 변수를 12345X13X22, 12345X13X23, 12345X13X24 대신 name, age, gender로 부를 수 있습니다. 이렇게 하면 모든 사람이 수식을 더 쉽게 읽고 논리를 검증할 수 있으며, 그룹 또는 질문 번호를 추적하지 않고도 질문의 순서를 자유롭게 바꿀 수 있습니다.
중요: 앞선 페이지나 질문에 있는 변수만 참조하는 것이 안전합니다.
또한 Expression Manager를 사용하면 질문의 다양한 속성에 접근할 수 있습니다:
| 구문 | 의미 | 예시 | 예시 결과 |
|---|---|---|---|
| Qcode | Qcode.code의 별칭 | {implode(',',name,gender)} | 'Tom','M' |
| Qcode.code | 질문이 관련성이 있는 경우 선택된 답변 코드(그렇지 않으면 빈 값), 코드가 있는 질문이 아닌 경우 텍스트 값 | {implode(',',name.code,gender.code)} | 'Tom','M' |
| Qcode.NAOK | Qcode와 동일 - NAOK에 대한 설명 참조 | {gender.NAOK} | 'M' |
| Qcode.value | 질문이 관련성이 있는 경우 질문의 평가 값(그렇지 않으면 빈 값), 코드가 있는 질문이 아닌 경우 텍스트 값 | {gender.value} | '1' |
| Qcode.valueNAOK | Qcode.value와 동일 - NAOK에 대한 설명 참조 | {gender.valueNAOK} | '1' |
| Qcode.shown | 질문의 표시 값 | {implode(',',name.shown,gender.shown)} | 'Tom','Male' |
| Qcode.question | 질문의 텍스트 | {gender.question} | 'What is your gender?' |
| Qcode.mandatory | 질문의 필수 여부 (Y/N) | {gender.mandatory} | 'N' |
| Qcode.qid | 내부 질문 번호 (순차 번호 아님) | {gender.qid} | 337 |
| Qcode.type | 질문 유형 | {gender.type} | 'G' |
| Qcode.jsName | 이 페이지 안팎에서 선언되었는지와 관계없이 질문에 대한 올바른 자바스크립트 이름 | {gender.jsName} | 'java1827X3X337' |
| Qcode.gid | 내부 그룹 번호 (순차 번호 아님) | {gender.gid} | 3 |
| Qcode.qseq | 0부터 시작하는 질문의 순차 번호 | {gender.qseq} | 5 |
| Qcode.gseq | 0부터 시작하는 그룹의 순차 번호 | {gender.gseq} | 1 |
| Qcode.relevanceStatus | 질문이 현재 관련성이 있는지 여부 (0 또는 1) | {gender.relevanceStatus} | 1 |
| Qcode.relevance | 질문 수준의 관련성 수식 | {gender.relevance} | '!is_empty(name)' |
| Qcode.grelevance | 그룹 수준의 관련성 수식 | {gender.grelevance} | 'num_children >= 5' |
| Qcode.sgqa | 이 질문의 SGQA 값 | {gender.sgqa} | '1827X3X337' |
HTML 편집기 문제
HTML 편집기를 사용하면 일부 문자가 HTML 엔티티로 대체됩니다.
- & → &
- < → <
- > → >
HTML 편집기를 사용하는 경우 다음과 같이 사용해야 합니다:
- &에는 and
- <에는 lt
- <=에는 le
- >에는 gt
- >=에는 ge
Qcode 변수 이름 규칙
다음은 질문 유형별로 Qcode를 구성하는 방법(및 일부 속성에 접근하는 방법)에 대한 세부 정보입니다. 일반적으로 Qcode는 다음과 같이 구성됩니다:
QuestionCode . '_' . SubQuestionCode . '_' . ScaleId
하위 질문 코드와 척도 ID의 사용 여부는 질문 유형에 따라 다릅니다. 아래 표를 참조하십시오. comment와 other의 경우 질문 코드는 QuestionCode_comment 및 QuestionCode_other입니다.
| 유형 | 설명 | 코드 | 하위 질문 | 응답 옵션 | 척도 | 응답 코드 | 표시되는 응답 | 관련성 |
|---|---|---|---|---|---|---|---|---|
| 5 | 5점 척도 라디오 버튼 | Q1 | 1-5 | {Q1} | {Q1.shown} | {Q1==3} | ||
| B | 배열(10점 척도) 라디오 버튼 | Q2 | L1-L6 | 1-10 | {Q2_L2} | {Q2_L2.shown} | {Q2_L2==7} | |
| A | 배열 (5점 척도) 라디오 버튼 | Q3 | 1-5 | 1-5 | {Q3_1} | {Q3_1.shown} | {Q3_1>=3} | |
| 1 | 배열 (유연한 레이블) 이중 척도 | Q4 | sq1-sq5 | 0:a1-a3 | 1:b1-b3 | {Q4_sq1_0} | {Q4_sq1_1.shown} | {Q4_sq1_1=='b2'} |
| H | 배열 (유연한) - 열 형식 | Q5 | 1-5 | s,m,t | {Q5_1} | {Q5_1.shown} | {Q5_1=='s'} | |
| F | 배열 (유연한) - 행 형식 | Q6 | F1-F5 | 1-5 | {Q6_F3} | {Q6_F3.shown} | {Q6_F3==4} | |
| E | 배열 (증가, 동일, 감소) 라디오 버튼 | Q7 | 1-7 | I,S,D | {Q7_4} | {Q7_4.shown} | {Q7_4=='D'} | |
| : | 배열 (다중 유연) 1~10 | Q8 | ls1,todo,ls2 | min,max,avg | {Q8_ls1_max} | {Q8_ls2_avg.shown} | {Q8_ls2_min==7} | |
| ; | 배열 (다중 유연) 텍스트 | Q9 | hp,st,sw | 1st,2nd,3rd | {Q9_hp_3rd} | {Q9_hp_3rd.shown} | {Q9_hp_3rd=='Peter'} | |
| C | 배열 (예/불확실/아니오) 라디오 버튼 | Q10 | 1-5 | Y,N,U | {Q10_1} | {Q10_1.shown} | {Q10_3=='Y'} | |
| X | 상용구 질문 | Q11 | {Q11.shown} | |||||
| D | 날짜 | Q12 | {Q12} | {Q12.shown} | ||||
| * | 수식 | Q13 | {Q13} | {Q13.shown} | {Q13>5} | |||
| ~124~ | 파일 업로드 (업로드된 파일 수를 기록) | Q14 | {Q14} | {Q14>0} | ||||
| G | 성(姓) 드롭-다운 목록 | Q15 | M,F | {Q15} | {Q15.shown} | {Q15=='M'} | ||
| U | 대량 자유 서술 | Q16 | {Q16} | {Q16.shown} | {strlen(Q16)>100} | |||
| I | 언어 질문 | Q17 | {Q17} | {Q17.shown} | {Q17=='en'} | |||
| ! | 목록 - 드롭다운 | Q18 | 1-5 | {Q18} | {Q18.shown} | {Q18==3} | ||
| L | 목록 드롭다운/라디오 버튼 목록 | Q19 | A-Z | {Q19} | {Q19.shown} | {Q19=='X'} | ||
| O | 해설있는 목록 드롭다운/라디오 버튼 목록 + 텍스트 영역 | Q20 | A-F | {Q20},{Q20comment} | {Q20.shown} | {Q20=='B'} | ||
| T | 장문 자유 서술 | Q21 | {Q21} | {Q21.shown} | {strstr(Q21,'hello')>0} | |||
| M | 다수 답안 체크박스 | Q22 | A-F, other | {Q22_E}, {Q22_other} | {Q22_E.shown}, {Q22_other.shown} | {Q22_E=='Y'} | ||
| P | 해설있는 다중 선택 체크박스 + 텍스트 | Q23 | A-F | {Q23_D}, {Q23_Dcomment} | {Q23_D.shown} | {!is_empty(Q23)} | ||
| K | 여러 숫자 질문 | Q24 | self,mom,dad | {Q24_self} | {Q24_self.shown} | {Q24_self>30} | ||
| Q | 짧은 서술 여러 개 | Q25 | A-F | {Q25_B} | {Q25_B.shown} | {substr(Q25_B,1,1)=='Q'} | ||
| N | 숫자 질문 유형 | Q26 | {Q26} | {Q26.shown} | {Q26 > 30} | |||
| R | 순위 스타일 | Q27 | 1-4 | {Q27_1} | {Q27_1.shown} | {Q27_1==3} | ||
| S | 짧은 자유 서술 | Q28 | {Q28} | {Q28.shown} | {Q28=='mine'} | |||
| Y | 예/아니오 라디오 버튼 | Q29 | {Q29} | {Q29.shown} | {Q29=='Y'} |
예약 변수 'this', 'self', 'that'
하위 질문 중 몇 개에 응답했는지 세거나 점수를 합산하는 것처럼 질문의 모든 부분을 평가해야 하는 경우가 많습니다. 또는 질문의 특정 행이나 열만 처리해야 할 때도 있습니다(예: 행 또는 열의 합계를 구해 데이터베이스에 저장). 이러한 예약 변수를 사용하면 이 과정을 비교적 쉽게 처리할 수 있습니다.
'this' 변수는 "전체 질문 유효성 방정식" 및 "하위 질문 유효성 방정식" 고급 질문 옵션 내에서만 사용됩니다. 이 변수는 해당 질문 내 각 셀의 변수 이름으로 확장됩니다. 따라서 각 항목이 3보다 큰지 확인하려면 "하위 질문 유효성 방정식"을 (this > 3)으로 설정하면 됩니다.
'self' 및 'that' 변수는 더욱 강력하며, 수식을 처리하기 전에 확장되는 매크로로 작동합니다. 사용 가능한 구문은 다음과 같습니다:
- self
- self.suffix
- self.sub-selector
- self.sub-selector.suffix
suffix는 일반적인 qcode 접미사(예: NAOK, value, shown) 중 하나입니다.
sub-selector는 다음 중 하나입니다:
- comments - 해설인 하위 질문만 (예: 해설있는 다중 선택 및 해설있는 목록)
- nocomments - 해설이 아닌 하위 질문만
- sq_X - X는 행 또는 열 식별자입니다. 패턴 X와 일치하는 하위 질문만 선택됩니다. 검색은 전체 코드 식별자를 대상으로 수행되며, sq_X는 nX, X, Xn 형태의 하위 질문과 일치하여 포함합니다 (예: sq_1을 사용하면 하위 질문 a1, 1a, 1, 11 또는 001이 포함됩니다). 하위 질문 코드가 QCODE_SQCODE_1 및 QCODE_SQCODE_1인 이중 척도 질문 유형과 하위 질문 코드가 QCODE_1, QCODE_2 ...인 순위 질문 유형에 주의하십시오.
- nosq_X - X는 행 또는 열 식별자입니다. 패턴 X와 일치하지 않는 하위 질문만 선택됩니다. 검색은 전체 코드 식별자를 대상으로 수행되며, nosq_X는 nX, X, Xn 형태의 하위 질문과 일치하여 포함하지 않습니다.
예시:
- 질문의 일부라도 응답되었는가? {count(self.NAOK)>0}
- 이 질문의 평가 점수는 얼마인가? {sum(self.value)}
이 변수들을 사용해 행과 열의 합계를 구할 수도 있습니다. 행이 A-E이고 열이 1-5인 숫자 배열이 있다고 가정해 보겠습니다.
- 총합계는 얼마인가? {sum(self.NAOK)}
- 행 B의 합계는 얼마인가? {sum(self.sq_B.NAOK)}
- 열 3의 합계는 얼마인가? {sum(self.sq_3.NAOK)}
'that' 변수는 'self' 변수와 비슷하지만 다른 질문을 참조할 수 있습니다. 구문은 다음과 같습니다:
- that.qname
- that.qname.suffix
- that.qname.sub-selector
- that.qname.sub-selector.suffix
qname은 하위 질문 확장자가 없는 질문 이름입니다. 예를 들어 'q1'이라는 질문을 만들었다면 'q1'이 그 qname입니다.
예시:
- 질문 q1의 일부라도 응답되었는가? {count(that.q1.NAOK)>0}
- q2의 평가 점수는 얼마인가? {sum(that.q2.NAOK)}
- q3의 총합계는 얼마인가? {sum(that.q3.NAOK)}
- q4에서 행 C의 합계는 얼마인가? {sum(that.q4.sq_C.NAOK)}
- q4에서 열 2의 합계는 얼마인가? {sum(that.q4.sq_2.NAOK)}
'self' 및 'that' 변수는 모든 관련성 수식, 유효성 검사 또는 맞춤화(tailoring)에서 사용할 수 있습니다.
한 가지 주의할 점은 논리 파일 표시 기능을 사용하면 'self'와 'that'이 확장된 값으로 표시된다는 것입니다. 이를 통해 실제로 생성될 수식을 확인하여 사용자와 Expression Manager가 변수의 존재 여부를 검증할 수 있습니다. 매우 긴 수식이 보일 수 있어 혼란스러울 수 있습니다. 그러나 질문을 편집하면 'self' 및/또는 'that'을 사용한 원래 수식을 볼 수 있습니다.
또한 (a) 수식에 사용되는 각 변수의 이름을 명시적으로 지정하려는 경우, 또는 (b) 하위 질문이 없는 변수(예: 단일 응답 질문)를 사용하는 경우에는 이러한 변수를 사용하지 않아야 합니다. 이러한 경우 변수 앞에 'that'을 붙이는 것은 과도하며, 예기치 않은 결과가 발생할 수 있습니다.
NAOK 사용
NAOK --> "Not Applicable"(NA, 해당 없음)이어도 괜찮음(OK)
NAOK를 사용하면 일부 또는 모든 변수가 관련 없는 상태(예: "Not Applicable"(NA, 해당 없음))여도 괜찮다(OK)는 의미입니다.
수식에 질문의 변수를 넣었을 때, 해당 질문(또는 하위 질문)이 조건에 의해 숨겨져 있으면 수식 전체가 비활성화됩니다.
예를 들어 Q1의 하위 질문 중 하나가 필터링되어 있으면 count(Q1_SQ1,Q1_SQ2,Q1_SQ3,Q1_SQ4)는 항상 빈 문자열을 반환합니다. 이러한 질문에서 선택된 하위 질문의 수를 세려면 count(Q1_SQ1.NAOK,Q1_SQ2.NAOK,Q1_SQ3.NAOK,Q1_SQ4.NAOK)를 사용할 수 있습니다. 하위 질문이 숨겨져 있으면 Expression Manager는 빈 문자열을 반환합니다.
NAOK를 사용하지 않으면 질문 또는 하위 질문 중 하나라도 숨겨져 있을 경우 Expression Manager는 항상 빈 문자열을 반환하며, 이는 false를 반환하는 것과 같습니다.
.shown은 항상 NAOK 방식(숨겨져 있으면 빈 문자열)을 사용합니다. 하지만 응답의 코드가 필요한 경우에는 질문 코드 뒤에 .NAOK를 추가하는 것이 좋습니다. 단, 그 동작이 필요하고 무엇을 하는지 정확히 알고 있는 경우는 예외입니다.
다른 예시와 자세한 정보는 연쇄 조건 재정의에서 확인할 수 있습니다.
함수 사용
Expression Manager는 아래에 나와 있는 것과 같이 수학 함수, 문자열 함수 및 사용자 정의 함수를 제공합니다. 이러한 함수는 서버 측(PHP)과 클라이언트 측(JavaScript)에서 동일하게 작동하도록 PHP와 JavaScript 버전이 모두 마련되어 있습니다. 새로운 함수는 쉽게 추가할 수 있습니다.
구현된 함수
현재 사용할 수 있는 함수는 다음과 같습니다.
| 함수 | 의미 | 구문 |
|---|---|---|
| abs | 절대값 | number abs(number) |
| acos | 아크코사인 | number acos(number) |
| addslashes | 슬래시로 문자열 따옴표 처리 | string addslashes(string) |
| asin | 아크사인 | number asin(number) |
| atan | 아크탄젠트 | number atan(number) |
| atan2 | 두 변수의 아크탄젠트 | number atan2(number, number) |
| ceil | 반올림 | number ceil(number) |
| checkdate | 그레고리력에서 유효한 날짜이면 true(1)를 반환합니다 | bool checkdate(month,day,year) |
| convert_value | inputTable과 outputTable의 숫자 값을 사용하여 숫자 값을 변환합니다 | number convert_value(fValue, iStrict, sTranslateFromList, sTranslateToList) |
| cos | 코사인 | number cos(number) |
| count | 목록에서 답변된(비어 있지 않은) 질문의 수를 계산합니다 | number count(arg1, arg12, ..., argN) |
| countif | 목록에서 첫 번째 인수와 같은 답변이 있는 질문의 수를 계산합니다 | number countif(matches, arg1, arg2, ... argN) |
| countifop | 목록에서 기준(arg op value)을 통과한 답변된 질문의 수를 계산합니다 | number countifop(op, value, arg1, arg2, ... argN) |
| date | 지역 날짜/시간 포맷 | string date(format [, timestamp=time()]) |
| exp | e 지수승 계산 | number exp(number) |
| fixnum | 필요한 경우 쉼표를 소수점 구분자로 사용하여 숫자를 표시합니다 | string fixnum(number) |
| floor | 반내림 | number floor(number) |
| gmdate | GMT 날짜/시간 포맷 | string gmdate(format [, timestamp=time()]) |
| html_entity_decode | 모든 HTML 엔티티를 해당 문자로 변환합니다 (항상 ENT_QUOTES와 UTF-8 사용) | string html_entity_decode(string) |
| htmlentities | 변환 가능한 모든 문자를 HTML 엔티티로 변환합니다 (항상 ENT_QUOTES와 UTF-8 사용) | string htmlentities(string) |
| expr_mgr_htmlspecialchars | 특수 문자를 HTML 엔티티로 변환합니다 (항상 ENT_QUOTES와 UTF-8 사용) | string htmlspecialchars(string) |
| expr_mgr_htmlspecialchars_decode | 특수 HTML 엔티티를 다시 문자로 변환합니다 (항상 ENT_QUOTES와 UTF-8 사용) | string htmlspecialchars_decode(string) |
| idate | 지역 시간/날짜를 정수로 표기 | string idate(string [, timestamp=time()]) |
| if (Updated in 3.0.2 ) | Excel 방식의 if(test,result_if_true[,result_if_false = ""]) | if(test,result_if_true[,result_if_false = ""]) |
| implode | 배열 요소를 문자열로 붙이기 | string implode(glue,arg1,arg2,...,argN) |
| intval | 변수의 정수 값을 구하기 | int intval(number [, base=10]) |
| is_empty | 변수가 비어 있는 것으로 간주되는지 확인합니다 | bool is_empty(var) |
| is_float | 변수의 유형이 float인지 확인합니다 | bool is_float(var) |
| is_int | 변수의 유형이 정수인지 확인합니다 | bool is_int(var) |
| is_nan | 값이 숫자가 아닌지 확인 | bool is_nan(var) |
| is_null | 변수가 NULL 이 아닌지 확인 | bool is_null(var) |
| is_numeric | 변수가 숫자 또는 숫자 문자열인지 확인합니다 | bool is_numeric(var) |
| is_string | 변수의 유형이 문자열인지 확인합니다 | bool is_string(var) |
| join (New in 2.0 build 130129) | 요소를 붙여 새 문자열로 만듭니다 | join(arg1, arg2, ... argN) |
| list | 비어 있지 않은 값을 쉼표로 구분한 목록을 반환합니다 | string list(arg1, arg2, ... argN) |
| listifop (New in 3.16.1 ) | 기준(cmpProp op value)을 통과한 목록 내 질문에서 지정한 질문 속성(retProp)을 'glue'로 구분한 목록으로 반환합니다 | string listifop(cmpProp, op, value, retProp, glue, sgqa1, sgqa2, ... sgqaN) |
| log | 지정한 밑에 대한 숫자의 로그, 밑이 없으면 자연로그입니다. | number log(number,base=e) |
| ltrim | 문자열의 시작 부분에서 공백(또는 다른 문자)을 제거합니다 | string ltrim(string [, charlist]) |
| max | 최댓값 찾기 | number max(arg1, arg2, ... argN) |
| min | 최솟값 찾기 | number min(arg1, arg2, ... argN) |
| mktime | 날짜의 UNIX 시간을 구합니다 (6개의 인수는 모두 선택 사항입니다) | number mktime([hour [, minute [, second [, month [, day [, year ]]]]]]) |
| modulo-function | modulo 함수는 아직 지원되지 않습니다. 대신 floor() 함수를 사용할 수 있습니다 | floor(x/y)==(x/y) |
| nl2br | 문자열의 모든 줄바꿈 앞에 HTML 줄바꿈을 삽입합니다 | string nl2br(string) |
| number_format | 숫자에 천 단위 구분기호 표시 | string number_format(number) |
| pi | PI의 가치 | number pi() |
| pow | 지수 표현 | number pow(base, exp) |
| quoted_printable_decode | quoted-printable 문자열을 8비트 문자열로 변환합니다 | string quoted_printable_decode(string) |
| quoted_printable_encode | 8비트 문자열을 quoted-printable 문자열로 변환합니다 | string quoted_printable_encode(string) |
| quotemeta | 메타 문자열 따옴표로 싸기 | string quotemeta(string) |
| rand | 난수 정수 생성하기, 이 예시를 참조하십시오 | int rand() OR int rand(min, max) |
| regexMatch | 문자열을 정규표현식과 비교합니다 | bool regexMatch(pattern,input) |
| round | 선택한 정확도로 숫자 반올림하기 | number round(val [, precision]) |
| rtrim | 문자열의 끝에서 공백(또는 다른 문자)을 제거합니다 | string rtrim(string [, charlist]) |
| sin | 사인 | number sin(arg) |
| sprintf | 형식화된 문자열 반환하기 | string sprintf(format, arg1, arg2, ... argN) |
| sqrt | 제곱근 | number sqrt(arg) |
| stddev | 숫자 목록의 표본 표준 편차를 계산합니다 | number stddev(arg1, arg2, ... argN) |
| str_pad | 문자열을 다른 문자열로 채워 지정한 길이로 만듭니다 | string str_pad(input, pad_length [, pad_string]) |
| str_repeat | 문자열 반복 | string str_repeat(input, multiplier) |
| str_replace | 검색 문자열과 일치하는 모든 부분을 대체 문자열로 바꿉니다 | string str_replace(search, replace, subject) |
| strcasecmp | Binary safe 대소문자를 구분하지 않는 문자열 비교 | int strcasecmp(str1, str2) |
| strcmp | Binary safe 문자열 비교 | int strcmp(str1, str2) |
| strip_tags | 문자열에서 HTML과 PHP 태그 없애기 | string strip_tags(str, allowable_tags) |
| stripos | 대소문자를 구분하지 않는 유니코드 문자열이 처음 나타나는 위치를 찾습니다 (0부터 시작, 찾지 못하면 false 반환) | int stripos(haystack, needle [, offset=0]) |
| stripslashes | 따옴표로 싸인 문자열에서 따옴표 없애기 | string stripslashes(string) |
| stristr | 대소문자를 구분하지 않는 strstr | string stristr(haystack, needle [, before_needle=false]) |
| strlen | 문자열 길이 구하기 | int strlen(string) |
| strpos | 유니코드 문자열이 처음 나타나는 위치를 찾습니다 (0부터 시작, 찾지 못하면 false 반환) | int strpos(haystack, needle [ offset=0]) |
| strrev | 문자열 뒤집기 | string strrev(string) |
| strstr | 문자열의 처음 위치 찻기 | string strstr(haystack, needle[, before_needle=false]) |
| strtolower | 문자열을 소문자로 변환합니다 | string strtolower(string) |
| strtotime | 영어로 된 날짜/시간 표현을 UNIX 시간으로 변환합니다 | int strtotime(string) |
| strtoupper | 문자열을 대문자로 변환합니다 | string strtoupper(string) |
| substr | 유니코드 문자열의 일부를 반환합니다 | string substr(string, start [, length]) |
| sum | 배열 안에 있는 값의 합 계산 | number sum(arg1, arg2, ... argN) |
| sumifop | 목록에서 기준(arg op value)을 통과한 답변된 질문의 값을 합산합니다 | number sumifop(op, value, arg1, arg2, ... argN) |
| tan | 탄젠트 | number tan(arg) |
| time | 현재 UNIX 시간 돌려주기 | number time() |
| trim | 문자열의 시작과 끝에서 공백(또는 다른 문자)을 제거합니다 | string trim(string [, charlist]) |
| ucwords | 문자열에서 각 단어의 첫 글자를 대문자로 변환합니다 | string ucwords(string) |
| unique | 모든 답변이 희소한 상태이면, true를 반환합니다 | boolean unique(arg1, ..., argN) |
계획 중이거나 검토 중인 함수
아직 구현되지는 않았지만 계획 중이거나 검토 중인 다른 함수는 다음과 같습니다. 이 중 일부는 다른 설문조사 도구와의 하위 호환성을 위한 것입니다.
| 구문 | 의미 | 비고 |
|---|---|---|
| e() | e의 값을 반환합니다 | |
| formatDate(X,PAT) | 날짜 X를 Java 날짜 형식 패턴 PAT에 따라 서식화한 문자열 값을 반환합니다 | |
| formatNumber(X,PAT) | 숫자 X를 Java 숫자 형식 패턴 PAT에 따라 서식화한 문자열 값을 반환합니다 | |
| getAnsOption(X) | 핵심 플러그인 ExpressionAnswerOptions | |
| getAnsOption(X,Y) | 핵심 플러그인 ExpressionAnswerOptions | |
| getRelevance(X) | 질문 X의 관련성 수식을 반환합니다 | |
| getStartTime() | 인터뷰가 시작된 시스템 시간에 해당하는 날짜를 반환합니다 | |
| getType(X) | 데이터 유형의 문자열 이름을 반환합니다 - 예: isNA()인 경우 *NA* | |
| gotoFirst() | 관련성이 있는 첫 번째 질문 집합으로 이동합니다 - 시스템의 일반적인 흐름을 벗어납니다 | |
| gotoNext() | 관련성이 있는 다음 질문 집합으로 이동합니다 - 시스템의 일반적인 흐름을 벗어납니다 | |
| gotoPrevious() | 관련성이 있는 이전 질문 집합으로 이동합니다 - 시스템의 일반적인 흐름을 벗어납니다 | |
| isAsked(X) | 응답이 *NA*, *INVALID*, *UNASKED* 중 어느 것도 아니면 true를 반환합니다 | |
| isInvalid(X) | 응답이 *INVALID* 유형이면 true를 반환합니다 | |
| isNA(X) | 응답이 *NA* 유형이면 true를 반환합니다 | |
| isNotUnderstood(X) | 응답이 *HUH* 유형이면 true를 반환합니다 | |
| isRefused(X) | 응답이 *REFUSED* 유형이면 true를 반환합니다 | |
| isSpecial(X) | 응답이 *UNASKED*, *NA*, *REFUSED*, *INVALID*, *UNKNOWN*, *HUH* 유형 중 하나이면 true를 반환합니다 | |
| isUnknown(X) | 응답이 *UNKNOWN* 유형이면 true를 반환합니다 | |
| jumpTo(X) | 지정한 질문이 포함된 그룹으로 이동합니다 -- 시스템의 일반적인 흐름을 벗어납니다 | |
| jumpToFirstUnasked() | 아직 묻지 않은 첫 번째 질문으로 이동합니다 |
|
| lastIndexOf(X,Y) | 문자열 X에서 문자열 Y의 마지막 인덱스(0부터 시작)를 반환합니다. Y가 X에 포함되어 있지 않으면 -1을 반환합니다 | |
| list(X,...) | 양수 값을 쉼표로 구분하고 마지막 두 값 사이에 "and"를 넣은 목록 문자열 | |
| mean(X,...) | 값 목록의 평균을 반환합니다 | |
| numAnsOptions(X) | 질문 X가 가진 응답 옵션의 수를 반환합니다 | |
| orlist(X,...) | 양수 값을 쉼표로 구분하고 마지막 두 값 사이에 "or"를 넣은 목록 문자열 | |
| parseDate(X,PAT) | 문자열 X를 Java 날짜 형식 패턴 PAT으로 구문 분석한 날짜 값을 반환합니다 | |
| parseNumber(X,PAT) | 문자열 X를 Java 숫자 형식 패턴 PAT으로 구문 분석한 숫자 값을 반환합니다 | |
| showAllResponsesExcept( questionList,attributeList,attributeTitleList) | )로 구분된 질문 식별자 목록, attributeList = 파이프로 구분된 속성 목록(question#, title, text, type 등 - 표시할 항목을 선택할 수 있습니다), attributeTitleList = 파이프로 구분된 표 머리글 목록(보고서를 다국어로 만들 수 있습니다). | |
| showTheseResponses( questionList,attributeList,attributeTitleList) | )로 구분된 질문 식별자 목록, attributeList = 파이프로 구분된 속성 목록(question#, title, text, type 등 - 표시할 항목을 선택할 수 있습니다), attributeTitleList = 파이프로 구분된 표 머리글 목록(보고서를 다국어로 만들 수 있습니다). |
Expression Manager는 어떤 변수가 로컬인지 알고 있습니다
페이지의 JavaScript를 올바르게 생성하려면 Expression Manager가 페이지에 어떤 변수가 설정되어 있는지, 그리고 해당 변수의 JavaScript ID가 무엇인지(예: document.getElementById(x))를 알아야 합니다. 또한 다른 페이지에 설정된 변수도 알아야 필요한 <input type='hidden' value='x'> 필드가 존재하고 값이 채워져 있는지 확인할 수 있습니다.
연쇄 조건
변수 중 하나라도 관련성이 없으면 전체 수식은 관련성이 없는 것(false)이 됩니다. 예를 들어 다음 표에서 N/A는 변수 중 하나가 관련성이 없음을 의미합니다.
| 연산자 | 예시 | a | b | 결과 |
|---|---|---|---|---|
| + (unary) | +a | N/A | false | |
| ! | !a | N/A | false | |
| == (또는 eq) | a == b | N/A | 5 | false |
| == (또는 eq) | a == b | N/A | 0 | false |
| == (또는 eq) | a == b | N/A | N/A | false |
| != (또는 ne) | a != b | N/A | 5 | false |
| != (또는 ne) | a != b | N/A | N/A | false |
| != (또는 ne) | a != b | N/A | 0 | false |
| > (또는 gt) | a > b | N/A | 5 | false |
| >= (또는 ge) | a >= b | N/A | 5 | false |
| < (또는 lt) | a < b | N/A | 5 | false |
| <= (또는 le) | a <= b | N/A | 5 | false |
| and | a and b | N/A | 5 | false |
| and | a and b | N/A | N/A | false |
| or | a or b | N/A | N/A | false |
| or | a or b | N/A | 5 | false |
| + | a + b | N/A | 5 | false |
| * | a * b | N/A | 5 | false |
| / | a / b | 5 | N/A | false |
| () | (a) | N/A | false | |
| (exp) | (a && b) | N/A | 5 | false |
| (exp) op (exp) | (b + b) > (a && b) | N/A | 5 | false |
| 함수 | sum(a,b,b) | N/A | 5 | false |
| 함수 | max(a,b) | N/A | 5 | false |
| 함수 | min(a,b) | N/A | 5 | false |
| 함수 | implode(', ',a,b,a,b) | N/A | 5 | false |
| 함수 | if(a,a,b) | N/A | 5 | false |
| 함수 | is_empty(a) | N/A | false | |
| 함수 | is_empty(a) | 0 (또는 공백) | true | |
| 함수 | !is_empty(a) | N/A | false |
연쇄 조건 재정의
관련성이 있는 모든 응답의 누적 합계를 표시하고 싶다고 가정해 보겠습니다. {sum(q1,q2,q3,...,qN)} 수식을 사용해 볼 수 있습니다. 그러나 이 수식은 내부적으로 LEMif(LEManyNA('q1','q2','q3',...,'qN'),,sum(LEMval('q1'),LEMval('q2'),LEMval('q3'),...,LEMval('qN')))로 변환됩니다. 따라서 q1-qN 값 중 하나라도 관련성이 없으면 수식은 항상 false를 반환합니다. 이 경우 sum()은 모든 질문에 응답할 때까지 0을 표시합니다.
이 문제를 피하려면 각 변수에 ".NAOK" 접미사(Not Applicable is OK, 즉 해당 없음도 괜찮다는 의미)를 붙일 수 있습니다. 이 경우 다음과 같이 동작합니다. 예를 들어 변수 q1.NAOK가 있다고 가정합니다.
- q1은 LEManyNA() 절에 추가되지 않습니다.
- LEMval('q1')은 계속해서 답변의 관련성 여부를 확인하며, 관련성이 없으면 ''를 반환합니다(따라서 관련성이 없는 개별 답변은 무시되지만 전체 표현식이 무효화되지는 않습니다).
따라서 누적 합계 문제의 해결책은 sum(q1.NAOK,q2.NAOK,q3.NAOK,...,qN.NAOK) 수식을 사용하는 것입니다.
.NAOK 접미사를 사용하면 여러 경로로 진행하다가 나중에 공통 경로로 합쳐지는 설문조사를 설계할 수도 있습니다. 예를 들어 응답자가 일반적인 응답 범위를 벗어나는 방식으로 설문조사에 응답했다고 가정합니다. 작성자는 응답자에게 유효한 결과를 얻지 못할 수 있음을 알리고 설문조사를 계속 진행할 것인지 물을 수 있습니다. 응답자가 '예'를 선택하면 나머지 질문이 표시됩니다. "나머지 질문"의 조건은 초기 응답이 일반 범위 내에 있었는지, 또는 일반 범위를 벗어난 경우에만 관련성이 있는 질문에 응답자가 '예'라고 답했는지를 확인합니다.
Expression Manager는 조건부 마이크로 맞춤화를 어떻게 지원합니까?
다음은 마이크로 맞춤화의 예입니다(질문 유형 'expr'은 수식을 의미합니다):
| 질문 코드 | 관련성 | 질문 유형 | 질문 |
|---|---|---|---|
| name | 1 | text | 이름이 무엇입니까? |
| age | 1 | text | 나이가 어떻게 되십니까? |
| badage | !is_empty(age) | expr | {(age<16) or (age>80)} |
| agestop | badage | message | 죄송합니다, {name}님. 이 테스트를 하기에는 연령이 너무 {if( (age<16),'young',if( (age>80),'old','middle-aged') ) } 입니다. |
| kids | !badage | yesno | 자녀가 있습니까? |
| parents | 1 | expr | {!badage && kids=='Y'} |
| numKids | parents | text | 자녀가 몇 명입니까? |
| kid1 | parents && numKids >= 1 | text | 첫째 자녀는 몇 살입니까? |
| kid2 | parents && numKids >= 2 | text | 둘째 자녀는 몇 살입니까? |
| kid3 | parents && numKids >= 3 | text | 셋째 자녀는 몇 살입니까? |
| kid4 | parents && numKids >= 4 | text | 넷째 자녀는 몇 살입니까? |
| kid5 | parents && numKids >= 5 | text | 다섯째 자녀는 몇 살입니까? |
| sumage | 1 | expr | {sum(kid1.NAOK,kid2.NAOK,kid3.NAOK,kid4.NAOK,kid5.NAOK)} |
| report | parents | yesno | {name}님은 {age}세이며 자녀가 {numKids}명이라고 답하셨습니다. 첫째부터 {min(numKids,5)}번째까지 자녀의 나이 합계는 {sumage}입니다. |
이 질문들은 모두 한 페이지(예: 같은 그룹)에 둘 수 있으며, 관련성이 있는 질문만 표시됩니다. 또한 자녀의 나이를 입력하는 동안 마지막 질문의 sum() 표현식이 페이지에서 동적으로 업데이트됩니다.
Expression Manager는 각 표현식을 이름이 지정된 <span> 요소로 감싸서 이 기능을 제공합니다. 값이 변경될 때마다 해당 <span> 요소에 표시되어야 하는 표현식을 다시 계산하고 화면을 다시 생성합니다. 한 페이지에 수십 개 또는 수백 개의 맞춤형 표현식이 있어도 페이지는 한 번의 화면 새로 고침으로 모두 다시 표시합니다.
LimeSurvey 1.91+와 Expression Manager 기능 대응표
| 이전 기능 | 새 기능 | 비고 |
|---|---|---|
| 조건 | 관련성 | 매우 복잡한 조건 수식을 사용할 수 있으며 더 넓은 범위의 변수에 접근할 수 있습니다 |
| 평가 | 수식 | 모든 평가 점수를 수식으로 재구성할 수 있습니다. 이렇게 하면 점수가 데이터베이스에 기록되며, 현재 페이지에서 점수 값이 동적으로 변하는 것도 볼 수 있습니다 |
| Replacements | Expression Manager | 핵심 엔진은 입력 문자열을 받아 중괄호 안의 모든 내용을 표현식으로 처리하므로 기존의 모든 치환 유형을 처리합니다. 내장된 JavaScript가 손상되지 않도록 Expression Manager는 (a) 중괄호 안에 앞뒤 공백이 없는 경우에만 중괄호 사이의 내용을 처리합니다. 예를 들어 {expr}은 표현식이지만 { expr}, {expr }, { expr }은 표현식이 아닙니다. 또한 Expression Manager는 자체 문자열 안의 내용은 처리하지 않습니다(예: {list('hi','there {braces}')}는 "hi there {braces}"를 생성합니다). 이스케이프된 중괄호(예: \{this is not an expression\})도 무시합니다 |
| 유효성 검사 | Expression Manager | 현재의 최소/최대 질문 속성을 Expression Manager가 처리하도록 할 계획입니다. 이렇게 하면 최소/최대 값 자체가 표현식이 될 수 있습니다 |
구문 강조
표현식을 입력하고 검증하는 데 도움이 되도록 EM은 다음 기능을 갖춘 구문 강조를 제공합니다:
구문 강조의 유형과 의미
| 색상 | 예시 | 의미 | 툴팁 | 설명 |
|---|---|---|---|---|
| 황갈색 배경 | Sample | 수식 전체 | 없음 | 중괄호 안에 있는 내용 중 수식으로 인식되는 모든 부분(예: 앞뒤에 공백이 없는 경우)은 주변 텍스트와 구분되도록 황갈색 배경으로 색상 표시됩니다. |
| 굵은 빨간색 텍스트 | Sample | 오류 | 오류에 대한 설명 | 알 수 없는 변수이거나 함수의 오류 등일 수 있습니다. 설문조사가 완전히 작동하지 않을 수 있으며, 이 표시는 일반 응답자에게는 보이지 않습니다. |
| 파란색 텍스트 | Sample | 함수 이름 | 의미와 허용되는 구문 | 함수 이름, 또는 여는 괄호가 뒤따르므로 함수여야 하는 항목은 굵은 파란색 텍스트로 표시됩니다. 툴팁에는 함수의 의미와 허용되는 구문이 표시됩니다. |
| 회색 텍스트 | Sample | 문자열 | 없음 | 작은따옴표 또는 큰따옴표로 묶인 문자열은 회색 텍스트로 표시됩니다. |
| 청록색 텍스트 | Sample | 같은 페이지에서 설정되는 변수 | [이름 또는 SGQA 코드]: 질문; 값; 각 값의 코드를 보여주는 답변 목록 | 현재 질문과 같은 페이지에서 설정되는 모든 변수는 청록색 텍스트로 표시되며, 이는 JavaScript에서 업데이트될 수 있음을 나타냅니다. 툴팁에는 변수 이름, 실제 질문, 현재값(설정되지 않은 경우 공백)이 표시됩니다. 질문 유형이 열거된 값 집합에서 응답을 받는 경우, 코드와 표시 값의 매핑도 함께 표시됩니다. |
| 녹색 텍스트 | Sample | 이전 페이지에서 설정된 변수 | [이름 또는 SGQA 코드]: 질문; 값; 각 값의 코드를 보여주는 답변 목록 | 이전 페이지에서 설정된 모든 변수는 굵은 녹색 텍스트로 표시됩니다. 툴팁에는 변수 이름, 실제 질문, 현재값(설정되지 않은 경우 공백)이 표시됩니다. 질문 유형이 열거된 값 집합에서 응답을 받는 경우, 코드와 표시 값의 매핑도 함께 표시됩니다. |
| 굵은 분홍색 텍스트 | Sample | 이후 페이지에서 설정되는 변수 일반적으로 설문조사 시작 시에는 비어 있지만, 인덱스나 이전 이동으로 채워질 수 있음 | [이름 또는 SGQA 코드]: 질문; 값; 각 값의 코드를 보여주는 답변 목록 | 다음 페이지에서 설정되는 모든 변수는 굵은 분홍색 텍스트로 표시됩니다. 툴팁에는 변수 이름, 실제 질문, 현재값(설정되지 않은 경우 공백)이 표시됩니다. 질문 유형이 열거된 값 집합에서 응답을 받는 경우, 코드와 표시 값의 매핑도 함께 표시됩니다. |
| 굵은 황갈색 텍스트 | Sample | Lime 대체 값 | 값 | Lime 대체 문자열({TOKEN:xxx}, {PRIVACY_MESSAGE} 등)은 굵은 황갈색 텍스트로 표시됩니다. |
| 빨간색 텍스트 | Sample | 할당 연산자 (=) | 경고 메시지 | 할당 연산자(=)를 사용하면 해당 연산자가 빨간색 텍스트로 표시됩니다. 이는 a == b인지 확인하려던 것을 실수로 a = b로 값을 설정하는 일을 방지하기 위한 것입니다. |
| 일반 검은색 텍스트 | Sample | 구두점 | 없음 | 수식 안의 그 밖의 모든 구두점은 일반 검은색 텍스트로 표시됩니다. |
| 빨간색 상자 텍스트 | 오류 주위를 굵은 빨간색 선이 둘러쌈 | 구문 오류 | 오류에 대한 설명 | 감지된 모든 구문 오류는 오류 주위에 빨간색 상자를 표시하여 나타냅니다. 툴팁에는 오류 내용이 표시됩니다. 예를 들어 짝이 맞지 않는 괄호, 정의되지 않은 함수의 사용, 함수에 잘못된 수의 인수 전달, 구조가 잘못된 수식(예: 변수 사이에 연산자 누락), 읽기 전용 변수에 새 값을 할당하려는 시도, 변수가 아닌 대상에 값을 할당하려는 시도, 또는 지원되지 않는 구문의 사용 등이 있습니다. 구문 오류 감지 시스템은 수식에 여러 오류가 있더라도 하나의 오류만 보고할 수 있지만, 오류가 감지되면 적어도 하나는 표시됩니다. |
추가 자료
Expression Manager 샘플 설문조사
사용 사례 및 사용 방법
단계별 예제
Expression Manager 통계 함수
개발자용 참조










