From 425e9876fe5475135d792a3e3372abddfef090ff Mon Sep 17 00:00:00 2001 From: dragdra Date: Wed, 18 Jun 2025 17:58:12 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B3=B0=EB=AF=B9=EC=8A=A4=20=EC=B1=84?= =?UTF-8?q?=EC=A0=90=20=EA=B8=B0=EC=A4=80=20=EC=88=98=EC=A0=95=EB=B2=84?= =?UTF-8?q?=EC=A0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 00_DIC_2505B_TEST.xlsx | Bin 21849 -> 26555 bytes DIC_2505B.json | 84 +++++----- psdExport_2.js | 362 +++++++++++++---------------------------- 3 files changed, 156 insertions(+), 290 deletions(-) diff --git a/00_DIC_2505B_TEST.xlsx b/00_DIC_2505B_TEST.xlsx index fb76c92d67641781615d17fa586e10c8237a5194..fb415eb0dbe42e2fdf2e058cfa0e01a11091e34b 100644 GIT binary patch delta 2406 zcmZ8jZ)jUp6mRasZJm}RwTXi^t}AwJnl^cVl9%_AmyDUTeYwv+jCEtuN;ik#1pjo7 zG5j(Ma|~Co-C=ghIwnj}!O=}oVG4pw6em;msUQ7^(q_zp;1?O5bMMVc^C9Q=e)pVr z?(d#^?#)~JD0J;+Xz|V7$n$*Tdkd+S7W!>zX=#DgC%3@oy?<(fmHXt~?LUXk^tZM; zJ>4%HI9BR$;9{TN>MG_EyWh|iHFU|11~-uR!QuXWxrLef+1JhG#q(a~XxYmgEPDsL z50`o>7<#1C^U9IKJ!S7`S=T4)BCGSmqb7+?rPw4ee zPu0(!SUEkjeD$mPJBu)sOhk2Ka%FCI`P#Xhe*5jS^@T5BGMRV)N9*S(_QdXsu2*fD1a;%Hh|UCb+|Z4FV7B=k1Qw4f*ec?b-_1- z6Y$nx7}7%}3S_Z=z{soqFVE6CXTYna04M5q(^Z-ujVYsY6 z4skn-3!K&|k}N070s{^>31~O2NaeU0PK?zgZ~>Uj6xn_x_kSk>O})rqxse9<#(uRBLhzi?y~$bWTjOIUA5zt!juWYr_)ZOg2e* zHJ^B@L#rv|DlQA%9}zspf$|c1L{8uP2 zBu=p^&dE&iVOeR}6TT^XrbdXB=ZXi2H0e^YGiusRMS%leJX9eIrneQI^TOJQnTKsU z7DBd+PfjdEqk)J8$SCE!*ZH8CZ%S!8RA;TCu&Qua;fO#?FT$8_Ld1??en;Fk-Iw%4(8w^=5!5Qd?`O zE%<{{TcjJ4Ok*P>!Sy4Fq#i*VVB2S`>{`z3x_?Y-$g-N6 zz{}QG&D;!Zcs?b+hQ^*wt0(;<%Ok10kTbn)yw@Qy37b8c@c6R;TmBzTf ze!SWkZ;Bsoj5nQ)k;b^QKF_EcAGe!c@Rh@I*S}Cxx{EpACX|rB~SK(rni!3YT1Cm~z{&=CU-uEPbDUSbH#2yFY_% zmjmnW4#eFi?7C0mrpj9$3q(&FrC`ESL)B+Qxpx6&?>qG~qIz}#D`_J(eBo7`Tf+BJk%89P46 z_7g#t_Z1VoFPGqR9h31+fyGtcN{a+IrL?2Kn=q^x@LM*ikF~1wLV-&ktzx6uB$yqABV zjyjb1e13uqCzoA2`QOySkiSU(NZ?97M$Zd)p~4|yGasfO%dix9`cE3!LY%%ggi^tI JxN='1']/CRTrackClip[1][not(@ClipIndex='-1')]", + "ele": "", + "type": "audio.StartTime", + "media": "음악.mp3", + "value": 0, "point": 2 }, "31": { - "ele": "//CRTrackArr/CRAudioTrackArr/CRTrackList[@Name='오디오1']/CRTrackClip[@Length='810']", + "ele": "//CRTrackList[@Name='오디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']", + "type": "audio.EndTime", + "media": "음악.mp3", + "value": 810, "point": 2 }, "32": { - "ele": "//CRTrackArr/CRAudioTrackArr/CRTrackList[@Name='오디오1']//CRFilter[@Type='2'][@ID='1'][@VID8='90']", - "point": 2 + "ele": "//CRTrackList[@Name='오디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter", + "type": "audio.Effect", + "media": "음악.mp3", + "value": { + "ID": "1", + "PlayTime": "90" + }, + "point": 2, + "desc": "ID속성-페이드인[0]/페이드아웃[1]" }, "33": { "ele": "none", diff --git a/psdExport_2.js b/psdExport_2.js index f18c993..997574e 100644 --- a/psdExport_2.js +++ b/psdExport_2.js @@ -182,7 +182,7 @@ function getGmepScore(gmepData, scoringJson, index) { tolerance = 0, // 숫자 비교 시 허용 오차 type = 'auto', // 'auto' | 'number[]' | 'string[]' | 'object' | 'primitive' } = options; - + if (type === 'force-correct') { isEqual = true; } @@ -196,7 +196,7 @@ function getGmepScore(gmepData, scoringJson, index) { } } else if (type === 'object' || (type === 'auto' && typeof right === 'object' && typeof user === 'object')) { isEqual = JSON.stringify(user) === JSON.stringify(right); - } else { + } else { isEqual = user == right; // primitive 비교 } @@ -238,12 +238,15 @@ function getGmepScore(gmepData, scoringJson, index) { const scoringData = scoringJson[index]; // console.log(scoringData); + // 동영상 시작시간, 오프닝 시작시간 상수값 저장 + const videoStartTime = scoringData['10'].value; + const openingStartTime = scoringData['28'].value; let totalScore = 0; // 채점기준표 문항별 분류 for (const key in scoringData) { - function getClipIndexByMediaPath(mediaName) { + function getCRClipIndex(mediaName) { // CRClipArr/CRClip 요소의 Path속성 리스트를 구함 // 모션 클립 이미지도 고려해 처리 const mediaPathList = xpath.select("//CRClipArr/CRClip[@Type='11']/CRCUnitArr/@Path | //CRClipArr/CRClip[not(@Type='11')]/@Path", gmepXmlDoc); @@ -297,7 +300,7 @@ function getGmepScore(gmepData, scoringJson, index) { // 자막의 인덱스를 구함 function getCilpIndexByStartTime(startTime) { const crTrackClips = xpath.select("//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip", gmepXmlDoc); - const subtitleStartTimeList = getSubtitleStartTime(); + const subtitleStartTimeList = getStartTimeList('텍스트'); const startTimeIndex = subtitleStartTimeList.findIndex(value => value === startTime); let subtitleClipIndex = null; @@ -316,8 +319,15 @@ function getGmepScore(gmepData, scoringJson, index) { } // 영상내 존재하는 자막과 자막사이 공백의 시작시간 리스트를 구함 - function getSubtitleStartTime() { - const trackClips = xpath.select(`//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip`, gmepXmlDoc); + function getStartTimeList(type) { + let trackClips = null; + + if (type === '텍스트') { + trackClips = xpath.select(`//CRTrackList[@Name='${type}' or @Name='비디오2']/CRTrackClip`, gmepXmlDoc); + } + else if (type === '비디오1' || type === '오디오1') { + trackClips = xpath.select(`//CRTrackList[@Name='${type}']/CRTrackClip`, gmepXmlDoc); + } let cumulativeLengths = []; let total = 0; @@ -333,29 +343,30 @@ function getGmepScore(gmepData, scoringJson, index) { return cumulativeLengths; } - function getTextTrackClipIndex(clipIndex) { - const crTrackClips = xpath.select(`//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip`, gmepXmlDoc); + function getCRTrackClipIndex(crclipIndex, type) { + let xpathQuery; + if (type === '텍스트') { + xpathQuery = `//CRTrackList[@Name='${type}' or @Name='비디오2']/CRTrackClip`; + } + else if (type === '비디오1' || type === '오디오1') { + xpathQuery = `//CRTrackList[@Name='${type}']/CRTrackClip`; + } + else { + throw new Error(`Unknown type: ${type}`); + } - let index = null; - for (let i = 0; crTrackClips.length; i++) { - if (clipIndex == parseInt(crTrackClips[i].getAttribute('ClipIndex'), 10)) { + const crTrackClips = xpath.select(xpathQuery, gmepXmlDoc); + + let index = -1; + // crTrackClips에서 ClipIndex가 crclipIndex와 일치하는 요소의 인덱스를 찾음 + // 처음 발견하는 요소의 인덱스를 반환 + for (let i = 0; i < crTrackClips.length; i++) { + if (crclipIndex == parseInt(crTrackClips[i].getAttribute('ClipIndex'), 10)) { index = i; break; } } - return index; - } - function getVideoTrackClipIndex(clipIndex) { - const crTrackClips = xpath.select(`//CRTrackList[@Name='비디오1']/CRTrackClip`, gmepXmlDoc); - - let index = null; - for (let i = 0; crTrackClips.length; i++) { - if (clipIndex == parseInt(crTrackClips[i].getAttribute('ClipIndex'), 10)) { - index = i; - break; - } - } return index; } @@ -369,8 +380,9 @@ function getGmepScore(gmepData, scoringJson, index) { let search = scoringData[key].search; const media = scoringData[key].media; - const videoStartTime = scoringData.videoStartTime; - const openingStartTime = scoringData.openingStartTime; + // const videoStartTime = scoringData.videoStartTime; + // const openingStartTime = scoringData.openingStartTime; + const image = scoringData[key].image; let userAnswer = null; @@ -474,7 +486,7 @@ function getGmepScore(gmepData, scoringJson, index) { } else if (type == "startEnd") { - const crclipIndex = getClipIndexByMediaPath(media); + const crclipIndex = getCRClipIndex(media); // 해당 미디어가 없을경우 clipIndex값 -1 if (crclipIndex == -1) { userAnswer = null; @@ -499,7 +511,7 @@ function getGmepScore(gmepData, scoringJson, index) { // 동영상 클립 이펙트 [2-4] // 이미지 클립 오버레이 [2-14, 17, 20] else if (type == "effect" || type === "imageOverlay") { - const crclipIndex = getClipIndexByMediaPath(media); + const crclipIndex = getCRClipIndex(media); // 해당 미디어가 없을경우 clipIndex값 -1 if (crclipIndex == -1) { userAnswer = null; @@ -510,6 +522,7 @@ function getGmepScore(gmepData, scoringJson, index) { const crFilter = xpath.select1(xpathExpr, gmepXmlDoc); if (!crFilter) { userAnswer = null; + totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult); } else { userAnswer = {} @@ -529,8 +542,8 @@ function getGmepScore(gmepData, scoringJson, index) { // 동영상 클립 트랜지션 [2-15, 18, 21] else if (type === 'clipTransition') { - const crclipIndex = getClipIndexByMediaPath(media); - let crtrackClipIndex = getVideoTrackClipIndex(crclipIndex); + const crclipIndex = getCRClipIndex(media); + let crtrackClipIndex = getCRTrackClipIndex(crclipIndex, "비디오1"); if (crtrackClipIndex == -1) { userAnswer = null; @@ -603,11 +616,10 @@ function getGmepScore(gmepData, scoringJson, index) { } } } - console.log('🟥🟧🟨🟩🟦🟪⬛') } else if (type == "Mute") { - const crclipIndex = getClipIndexByMediaPath(media); + const crclipIndex = getCRClipIndex(media); if (crclipIndex == -1) { userAnswer = null; } @@ -620,7 +632,7 @@ function getGmepScore(gmepData, scoringJson, index) { } // 이미지 클립 길이 [2-13, 16, 19] else if (type === 'imageLength') { - const crclipIndex = getClipIndexByMediaPath(media); + const crclipIndex = getCRClipIndex(media); if (crclipIndex == -1) { userAnswer = null; } @@ -632,6 +644,45 @@ function getGmepScore(gmepData, scoringJson, index) { totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult); } + else if (type.includes('audio')) { + const crclipIndex = getCRClipIndex(media); + const crtrackClipIndex = getCRTrackClipIndex(crclipIndex, "오디오1") + const startTimeList = getStartTimeList('오디오1'); + + if (type.includes('StartTime')) { + const startTime = startTimeList[crtrackClipIndex]; + userAnswer = startTime; + } + else if (type.includes('EndTime')) { + const xpathQuery = ele?.replace(/{CRClipIndex}/g, crclipIndex); + const crTrackClip = xpath.select1(xpathQuery, gmepXmlDoc); + if (!crTrackClip) { + userAnswer = null; + } else { + const length = parseInt(crTrackClip.getAttribute('Length'), 10); + userAnswer = length; + } + } + else if (type.includes('Effect')) { + const xpathQuery = ele?.replace(/{CRClipIndex}/g, crclipIndex); + const fadeoutEffect = xpath.select1(xpathQuery, gmepXmlDoc); + if (!fadeoutEffect) { + userAnswer = null; + } + else { + const attributes = fadeoutEffect.attributes; + const id = attributes.getNamedItem('ID').value; + const playtime = attributes.getNamedItem('VID8').value; + + userAnswer = { + "ID": id, + "PlayTime": playtime, + }; + } + } + totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult); + } + else if (type.includes('opening') || type.includes('video')) { // 자막의 정보를 이용해 CROwneUnit의 인덱스를 구함 // 1. 텍스트 @@ -652,8 +703,8 @@ function getGmepScore(gmepData, scoringJson, index) { // 요소들의 시작시간을 갖고 있는 startTimeList를 구하고 // 해당 인덱스의 자막 시작시간을 구함 if (type.includes('StartTime')) { - const crtrackClipIndex = getTextTrackClipIndex(index) - const startTimeList = getSubtitleStartTime(); + const crtrackClipIndex = getCRTrackClipIndex(index, "텍스트") + const startTimeList = getStartTimeList('텍스트'); const startTime = startTimeList[crtrackClipIndex]; userAnswer = startTime; @@ -662,14 +713,14 @@ function getGmepScore(gmepData, scoringJson, index) { // 자막 길이 [2-11] [2-29] // 요소의 Length 속성을 구함 else if (type.includes('Length')) { - const crtrackClipIndex = getTextTrackClipIndex(index) + 1 // XML 1-based index + const crtrackClipIndex = getCRTrackClipIndex(index, "텍스트") + 1 // XML 1-based index const clipLength = xpath.select1(`//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip[${crtrackClipIndex}]/@Length`, gmepXmlDoc); userAnswer = parseInt(clipLength.value, 10); totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult); } // 자막 텍스트(글자, 폰트, 크기, 색상) [2-5, 6, 7, 8] [2-22, 23, 24, 25] - else if (type.includes('Text') || type.includes('Color')) { + else if (type.includes('Text')) { const xmlIndex = index + 1 // XML 1-based index const subtitleXpath = ele?.replace(/{index}/g, xmlIndex); const subtitleResult = xpath.select1(subtitleXpath, gmepXmlDoc); @@ -679,10 +730,31 @@ function getGmepScore(gmepData, scoringJson, index) { const hex = convertColorToHex(subtitleResult.value); userAnswer = hex; } + else if (type.includes('Outline')) { + const attributes = subtitleResult.attributes; + const width = Math.round(parseFloat(attributes.getNamedItem('VID100').value * 100)).toString(); + const color = convertColorToHex(attributes.getNamedItem('VID101').value); + + userAnswer = { + "width": width, + "color": color, + }; + } + else if (type.includes('FadeInEffect')) { + const attributes = subtitleResult.attributes; + const id = attributes.getNamedItem('VID505').value; + const playtime = attributes.getNamedItem('VID507').value; + + userAnswer = { + "ID": id, + "PlayTime": playtime, + }; + } else { userAnswer = subtitleResult.value; } - } else { + } + else { userAnswer = null; } @@ -699,6 +771,7 @@ function getGmepScore(gmepData, scoringJson, index) { userAnswer = subtitleResult.map(r => r.value); const errorRange = 0.1; + // userAnswer가 정수형 배열인 경우 type을 'number[]'로 설정 totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult, { tolerance: errorRange, type: 'number[]', @@ -710,222 +783,7 @@ function getGmepScore(gmepData, scoringJson, index) { } } - else if (type == "color") { - const result = xpath.select(ele, gmepXmlDoc); - if (result.length == 0) { - scoringResult[key] = 0; - continue; - } - - console.log(`value: ${rightAnswer} result: ${result[0].value}`); - // value와 result[0].value를 비교하여 같으면 점수 point 부여 - totalScore += result.length > 0 && rightAnswer === result[0].value ? point : 0; - scoringResult[key] = result.length > 0 && rightAnswer === result[0].value ? point : 0; - - } - else if (type == "multi") { - try { - const result = xpath.select(ele, gmepXmlDoc); - let isSame = true; - // console.log(`ele: ${ele}, value: ${value} result: ${result}`); - - if (result.length == 0) { - console.log('result length 0'); - scoringResult[key] = 0; - continue; - } - - result.forEach((v, i) => { - // value[i] 값이 정수형인 경우에는 float로 변환하여 비교 - // 정수형 v값을 float 형으로 변환하고 소수점 3자리까지 버림 - let temp = v.value; - let answer = rightAnswer[i]; - - if (Number.isFinite(rightAnswer[i]) && !Number.isInteger(rightAnswer[i])) { - temp = parseFloat(v.value); - answer = parseFloat(rightAnswer[i]); - // 소수점 3자리까지 버림 - temp = Math.floor(temp * 1000) / 1000; - } - // answer 문자열 중 : 가 포함되어 있다면 각각 분리하고 그 값의 차이를 구함 - if (typeof answer == "string" && answer.indexOf(':') > -1) { - const [answerStart, answerEnd] = answer.split(':').map(Number); - const [tempStart, tempEnd] = temp.split(':').map(Number); - answer = answerEnd - answerStart; - temp = tempEnd - tempStart; - } - - console.log(`temp: ${temp} answer: ${answer}`); - if (answer !== temp) { - console.log(`answer !== temp`); - isSame = false; - } - }); - totalScore += isSame ? point : 0; - scoringResult[key] = isSame ? point : 0; - } catch (e) { - console.log('err :', e); - scoringResult[key] = 0; - } - } - else if (type == "searchIndex") { - // let existEle = scoringData[key].existEle; - // XPath를 사용하여 ELE 요소가 존재하는지 확인 - const crcUnitArrNode = xpath.select1(existEle, gmepXmlDoc); - - if (crcUnitArrNode) { - // ELE 요소가 몇번째 요소인지 찾고 필요한 요소 확인 - const unitOrderNode = xpath.select1(ele, gmepXmlDoc); - console.log(`unitOrderNode: ${unitOrderNode}`); - if (unitOrderNode === undefined) { - scoringResult[key] = 0; - continue; - } - if (unitOrderNode.value === rightAnswer) { - console.log(`unit: ${unitOrderNode.value} === ${rightAnswer}`); - scoringResult[key] = point; - totalScore += point; - } - else if (unitOrderNode === rightAnswer) { - console.log(`unitValue: ${unitOrderNode} === ${rightAnswer}`); - scoringResult[key] = point; - totalScore += point; - } - else { - scoringResult[key] = 0; - } - - } - else { - console.log(`not found. ${existEle} `); - let result; - - if (ele2 !== undefined) { - result = xpath.select1(ele2, gmepXmlDoc); - } - - if (result == rightAnswer) { - totalScore += point; - scoringResult[key] = point; - } - else { - scoringResult[key] = 0; - } - } - } - - // 문제의 타입이 video(동영상자막) 또는 opening(오프닝자막)일 경우 - else if (type == "video" || type == "opening") { - - // 찾으려는 자막이 존재하지 않는 경우 - // (2-28) 문항의 경우 오프닝 자막이 없어도 xpath구문의 sum함수 결과값이 0이 반환되는것을 방지 - if (trackClipNode === undefined && textClipIndex === null) { - scoringResult[key] = 0; - continue; - } - const result = ele ? xpath.select(ele, gmepXmlDoc) : []; - const result2 = ele2 ? xpath.select(ele2, gmepXmlDoc) : []; - const result3 = ele3 ? xpath.select(ele3, gmepXmlDoc) : []; - - // 결과값이 배열이 아닌 경우 배열로 변환 - // 예시) (2-9)는 xpath를 통해 클립(자막) 시작시간(number숫자자료형)을 반환받으므로 배열로 변환하여 비교 - const resultValues = Array.isArray(result) ? - result.map(r => (typeof r === 'object' ? r.value : r)) : [result]; - const resultValues2 = Array.isArray(result2) ? - result2.map(r => (typeof r === 'object' ? r.value : r)) : [result2]; - const resultValues3 = Array.isArray(result3) ? - result3.map(r => (typeof r === 'object' ? r.value : r)) : [result3]; - - // 결과값들을 하나의 배열로 합침 - const allResults = [...[resultValues], ...[resultValues2], ...[resultValues3]]; - // console.log("🚀 ~ allResults:", allResults) - - // 정답(rightAnswer)의 값이 단일값이 아닐 경우 값 비교를 위해 배열로 변환 - // 예시) (2-11) 자막의 위치 좌표값 비교를 위해 [x, y] 값을 가져오므로 배열로 변환하여 비교 - const rightAnswerArray = Array.isArray(rightAnswer) ? rightAnswer : [rightAnswer]; - - // 결과값이 범위값인 경우 소수점 3자리까지 비교 - const formattedResults = allResults.map(result => { - // result의 길이가 1이상인 조건은 result값이 [x, y](좌표값, 두개 이상의 값)인 경우를 말한다 - if (Array.isArray(result) && result.length > 1) { - return result.map(r => { - // xml파일에 저장된 곰믹스 좌표값이 소수점 3자리 아래 버리는 형식이므로 - // 동일하게 결과값 소수점 3자리 아래 버린 후 반환 - const parsedValue = parseFloat(r); - if (parsedValue >= 0 && parsedValue < 1) { - // 소수점 3자리 아래 버림 - return (Math.floor(parsedValue * 1000) / 1000).toFixed(3); - } - return r; - }); - } - return result; - }); - console.log("🚀 ~ formattedResults:", formattedResults) - - // 배열 비교 함수 - function arraysEqual(arr1, arr2) { - if (arr1.length !== arr2.length) return false; - if (arr2.length === 1) { - for (let i = 0; i < arr1.length; i++) { - if (arr1[i] !== arr2[i]) return false; - } - return true; - } - else if (arr2.length > 1) { - for (let i = 0; i < arr1.length; i++) { - // 좌표값 범위 비교 - const errorRange = 0.1; - if (Math.abs(arr1[i] - arr2[i]) > errorRange) return false; - } - return true; - } - } - - // allResults에 rightAnswerArray와 일치하는 배열이 있는지 확인 - const isIncluded = formattedResults.some(arr => arraysEqual(arr, rightAnswerArray)); - - if (isIncluded) { - console.log("🚀 ~ getGmepScore ~ 정답:", rightAnswerArray); - totalScore += point; - scoringResult[key] = point; - } else { - console.log("🚀 ~ getGmepScore ~ 오답:", rightAnswerArray); - scoringResult[key] = 0; - } - } - - else { - try { - console.log('Unknown type:', ele); - let result = ele ? xpath.select(ele, gmepXmlDoc) : null; - let result2 = null; - let isCheck = false; - - if (!result || result.length === 0) { - isCheck = true; - } - if (isCheck && ele2) { - result2 = ele2 ? xpath.select(ele2, gmepXmlDoc) : null; - - if (!result2 || result2.length == 0) { - scoringResult[key] = 0; - continue; - } - result = result2; - // console.log(`1st isChecked: ${isCheck}, result: ${result}`) - } - // value와 result[0].value를 비교하여 같으면 점수 point 부여 - // console.log(`${(value === result[0].value)}, ${result.length > 0 && value === result[0].value} `) - // console.log(`2nd isChecked: ${isCheck}, result: ${result}`) - totalScore += result?.length > 0 ? point : 0; - scoringResult[key] = result?.length > 0 ? point : 0; - } catch (error) { - console.error(`Error processing XPath query for ele: ${ele}`, error); - scoringResult[key] = 0; - } - } } scoringResult['총점'] = totalScore; return scoringResult;