곰픽 JSON 채점기준표, 소스코드 수정

This commit is contained in:
2025-04-14 17:33:42 +09:00
parent 9158b42941
commit 547cd05a8b
6 changed files with 107 additions and 75 deletions

Binary file not shown.

View File

@@ -452,7 +452,7 @@
"desc": "자유 변형 문항은 채점 불가" "desc": "자유 변형 문항은 채점 불가"
}, },
"3": { "3": {
"type": "isExist", "type": "exists",
"ele": "//Layer/Name/@value", "ele": "//Layer/Name/@value",
"value": "Germs", "value": "Germs",
"point": 5, "point": 5,
@@ -476,7 +476,7 @@
"desc": "올가미 도구/이미지 문항은 채점 불가" "desc": "올가미 도구/이미지 문항은 채점 불가"
}, },
"6": { "6": {
"type": "isExist", "type": "exists",
"ele": "//Layer/Effects/Item/Name/@value", "ele": "//Layer/Effects/Item/Name/@value",
"value": "세피아", "value": "세피아",
"point": 6, "point": 6,
@@ -509,7 +509,7 @@
"10": { "10": {
"type" : "multiValue", "type" : "multiValue",
"ele": "//Layer/BlendOp/@value | //Layer/Opacity/@value", "ele": "//Layer/BlendOp/@value | //Layer/Opacity/@value",
"value" : [ "value": [
"중첩", "중첩",
"75" "75"
], ],
@@ -544,7 +544,7 @@
"desc": "배경색 문항은 채점 불가" "desc": "배경색 문항은 채점 불가"
}, },
"3": { "3": {
"type": "isExist", "type": "exists",
"ele": "//Layer/MaskOpType/@value", "ele": "//Layer/MaskOpType/@value",
"value": "Layering", "value": "Layering",
"point": 6 "point": 6
@@ -555,7 +555,7 @@
"desc": "가로방향 흐릿하게 문항은 채점 불가" "desc": "가로방향 흐릿하게 문항은 채점 불가"
}, },
"5": { "5": {
"type": "isExist", "type": "exists",
"ele": "//Layer//shape_type/@value", "ele": "//Layer//shape_type/@value",
"value": "ROUNDED_RECTANGLE", "value": "ROUNDED_RECTANGLE",
"point": 3 "point": 3
@@ -582,25 +582,26 @@
"point": 6 "point": 6
}, },
"8": { "8": {
"type": "exact", "type": "exists",
"ele": "//Layer//Shape[shape_type/@value='TEXT']/lines/Item/@value", "ele": "//Layer//Shape[shape_type/@value='TEXT']/lines/Item/@value",
"value": "어린이 과학관", "value": "어린이 과학관",
"point": 5 "point": 5
}, },
"9": { "9": {
"type": "exact", "type": "exists",
"ele": "//Layer//Shape[shape_type/@value='TEXT']/font/Name/@value", "ele": "//Layer//Shape[shape_type/@value='TEXT']/font/Name/@value",
"value": "돋움", "value": "돋움",
"point": 3 "point": 3
}, },
"10": { "10": {
"type": "exact", "type": "exists",
"ele": "//Layer//Shape[shape_type/@value='TEXT']/font/Italic/@value", "ele": "//Layer//Shape[shape_type/@value='TEXT']/font/{style}/@value",
"style": "Italic",
"value": "True", "value": "True",
"point": 3 "point": 3
}, },
"11": { "11": {
"type": "exact", "type": "exists",
"ele": "//Layer//Shape[shape_type/@value='TEXT']/font/Size/@value", "ele": "//Layer//Shape[shape_type/@value='TEXT']/font/Size/@value",
"value": "32", "value": "32",
"point": 3 "point": 3
@@ -613,7 +614,7 @@
"desc": "색상 코드 비교 시 소문자로 입력할 것" "desc": "색상 코드 비교 시 소문자로 입력할 것"
}, },
"13": { "13": {
"type": "exact", "type": "exists",
"ele": "//Layer//Shape[shape_type/@value='TEXT']/outline_peninfo/Width/@value", "ele": "//Layer//Shape[shape_type/@value='TEXT']/outline_peninfo/Width/@value",
"value": "3", "value": "3",
"point": 3 "point": 3
@@ -626,12 +627,14 @@
"desc": "색상 코드 비교 시 소문자로 입력할 것" "desc": "색상 코드 비교 시 소문자로 입력할 것"
}, },
"15": { "15": {
"ele": "//Layer[MaskOpType/@value='Clipping'][last()]", "type":"boolean",
"ele": "//Layer[MaskOpType/@value='Clipping']",
"point": 6, "point": 6,
"desc": "클리핑 마스크 항목은 별도 레이어로 추가되고 해당 속성을 추가해놓은 레이어가 있는지 여부 체크 함" "desc": "클리핑 마스크 항목은 별도 레이어로 추가되고 해당 속성을 추가해놓은 레이어가 있는지 여부 체크 함"
}, },
"16": { "16": {
"ele": "//Layer[contains(Name/@value, 'Layer 5')]//shape_type/@value", "type": "exists",
"ele": "//Layer/Shapes/Shape/shape_type/@value",
"value": "RECTANGLE", "value": "RECTANGLE",
"point": 3 "point": 3
}, },
@@ -646,13 +649,14 @@
"desc": "레이어 쉐이프 X, Y 좌표를 가지고 너비, 높이 계산하여 정답 채점" "desc": "레이어 쉐이프 X, Y 좌표를 가지고 너비, 높이 계산하여 정답 채점"
}, },
"18": { "18": {
"ele": "//Layer[contains(Name/@value, 'Layer 5')]//outline_peninfo/Width/@value", "type": "exists",
"ele": "//Layer//outline_peninfo/Width/@value",
"value": "7", "value": "7",
"point": 3 "point": 3
}, },
"19": { "19": {
"type": "color", "type": "color",
"ele": "//Layer//Shape[shape_type/@value='RECTANGLE'][contains(draw_type/@value, 'Outline')]/primary_color/@value", "ele": "//Layer//Shape[contains(draw_type/@value, 'Outline')]/primary_color/@value",
"value": "008878", "value": "008878",
"point": 3, "point": 3,
"desc": "색상 코드 비교 시 소문자로 입력할 것(채우기:secondary_color, 외곽선:primary_color)" "desc": "색상 코드 비교 시 소문자로 입력할 것(채우기:secondary_color, 외곽선:primary_color)"
@@ -660,11 +664,11 @@
"20": { "20": {
"type": "shadow", "type": "shadow",
"ele": { "ele": {
"shadow": "//Layer//Shape[shape_type/@value='RECTANGLE'][contains(draw_type/@value, 'Shadow')]", "shadow": "//Layer//Shape[contains(draw_type/@value, 'Shadow')]",
"width": "//Layer//Shape[shape_type/@value='RECTANGLE'][contains(draw_type/@value, 'Shadow')]/shadow_width/@value", "width": "//Layer//Shape[contains(draw_type/@value, 'Shadow')]/shadow_width/@value",
"distance": "//Layer//Shape[shape_type/@value='RECTANGLE'][contains(draw_type/@value, 'Shadow')]/shadow_distance/@value", "distance": "//Layer//Shape[contains(draw_type/@value, 'Shadow')]/shadow_distance/@value",
"blur": "//Layer//Shape[shape_type/@value='RECTANGLE'][contains(draw_type/@value, 'Shadow')]/shadow_blur/@value", "blur": "//Layer//Shape[contains(draw_type/@value, 'Shadow')]/shadow_blur/@value",
"angle": "//Layer//Shape[shape_type/@value='RECTANGLE'][contains(draw_type/@value, 'Shadow')]/shadow_angle/@value" "angle": "//Layer//Shape[contains(draw_type/@value, 'Shadow')]/shadow_angle/@value"
}, },
"value": { "value": {
"width": "5", "width": "5",

View File

@@ -251,7 +251,10 @@
"ele2": "sum(//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip[not(@ClipIndex='-1')][@ClipIndex={clipIndex}]/preceding-sibling::CRTrackClip/@Length)", "ele2": "sum(//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip[not(@ClipIndex='-1')][@ClipIndex={clipIndex}]/preceding-sibling::CRTrackClip/@Length)",
"search": "숲 속으로 떠나는 여행", "search": "숲 속으로 떠나는 여행",
"type": "videoIsExist", "type": "videoIsExist",
"value": [179, 180], "value": [
179,
180
],
"point": 2, "point": 2,
"desc": "출제 오류로 인해 두 가지 정답 모두 인정" "desc": "출제 오류로 인해 두 가지 정답 모두 인정"
}, },
@@ -454,7 +457,7 @@
"desc": "자유 변형 문항은 채점 불가" "desc": "자유 변형 문항은 채점 불가"
}, },
"3": { "3": {
"type": "isExist", "type": "exists",
"ele": "//Layer/Name/@value", "ele": "//Layer/Name/@value",
"value": "Tracking", "value": "Tracking",
"point": 5, "point": 5,
@@ -478,7 +481,7 @@
"desc": "올가미 도구/이미지 문항은 채점 불가" "desc": "올가미 도구/이미지 문항은 채점 불가"
}, },
"6": { "6": {
"type": "isExist", "type": "exists",
"ele": "//Layer/Effects/Item/Name/@value", "ele": "//Layer/Effects/Item/Name/@value",
"value": "세피아", "value": "세피아",
"point": 6, "point": 6,
@@ -493,8 +496,7 @@
}, },
"8": { "8": {
"type": "size", "type": "size",
"posX": "//Layer//op_points[Item]/Item[last()]/X/@value - //Layer//op_points[Item]/Item[1]/X/@value", "ele": "//Layer//op_points",
"posY": "//Layer//op_points[Item]/Item[last()]/Y/@value - //Layer//op_points[Item]/Item[1]/Y/@value",
"value": { "value": {
"width": 80, "width": 80,
"height": 80 "height": 80
@@ -547,7 +549,9 @@
"desc": "배경색 문항은 채점 불가" "desc": "배경색 문항은 채점 불가"
}, },
"3": { "3": {
"ele": "//Layer[contains(Name/@value, 'Layer 2')][MaskOpType/@value='Layering']", "type": "exists",
"ele": "//Layer/MaskOpType/@value",
"value": "Layering",
"point": 6 "point": 6
}, },
"4": { "4": {
@@ -556,14 +560,14 @@
"desc": "가로방향 흐릿하게 문항은 채점 불가" "desc": "가로방향 흐릿하게 문항은 채점 불가"
}, },
"5": { "5": {
"ele": "//Layer[contains(Name/@value, 'Layer 3')]//shape_type/@value", "type": "exists",
"answer": "RECTANGLE", "ele": "//Layer//shape_type/@value",
"value": "RECTANGLE",
"point": 3 "point": 3
}, },
"6": { "6": {
"type": "size", "type": "size",
"posX": "//Layer[contains(Name/@value, 'Layer 3')]//op_points[Item]/Item[last()]/X/@value - //Layer[contains(Name/@value, 'Layer 3')]//op_points[Item]/Item[1]/X/@value", "ele": "//Layer//op_points",
"posY": "//Layer[contains(Name/@value, 'Layer 3')]//op_points[Item]/Item[last()]/Y/@value - //Layer[contains(Name/@value, 'Layer 3')]//op_points[Item]/Item[1]/Y/@value",
"value": { "value": {
"width": 300, "width": 300,
"height": 50 "height": 50
@@ -573,8 +577,9 @@
}, },
"7": { "7": {
"type": "gradient", "type": "gradient",
"startColor": "//Layer[contains(Name/@value, 'Layer 3')]//gradient_start_color/@value", "ele": "//Layer/Shapes/Shape",
"endColor": "//Layer[contains(Name/@value, 'Layer 3')]//gradient_end_color/@value", "startColor": "gradient_start_color/@value",
"endColor": "gradient_end_color/@value",
"value": { "value": {
"startColor": "fff000", "startColor": "fff000",
"endColor": "009998" "endColor": "009998"
@@ -582,25 +587,26 @@
"point": 6 "point": 6
}, },
"8": { "8": {
"type": "exact", "type": "exists",
"ele": "//Layer//Shape[shape_type/@value='TEXT']/lines/Item/@value", "ele": "//Layer//Shape[shape_type/@value='TEXT']/lines/Item/@value",
"value": "김유정실레이야기길", "value": "김유정실레이야기길",
"point": 5 "point": 5
}, },
"9": { "9": {
"type": "exact", "type": "exists",
"ele": "//Layer//Shape[shape_type/@value='TEXT']/font/Name/@value", "ele": "//Layer//Shape[shape_type/@value='TEXT']/font/Name/@value",
"value": "궁서체", "value": "궁서체",
"point": 3 "point": 3
}, },
"10": { "10": {
"type": "exact", "type": "exists",
"ele": "//Layer//Shape[shape_type/@value='TEXT']/font/Bold/@value", "ele": "//Layer//Shape[shape_type/@value='TEXT']/font/{style}/@value",
"style": "Bold",
"value": "True", "value": "True",
"point": 3 "point": 3
}, },
"11": { "11": {
"type": "exact", "type": "exists",
"ele": "//Layer//Shape[shape_type/@value='TEXT']/font/Size/@value", "ele": "//Layer//Shape[shape_type/@value='TEXT']/font/Size/@value",
"value": "24", "value": "24",
"point": 3 "point": 3
@@ -613,7 +619,7 @@
"desc": "색상 코드 비교 시 소문자로 입력할 것" "desc": "색상 코드 비교 시 소문자로 입력할 것"
}, },
"13": { "13": {
"type": "exact", "type": "exists",
"ele": "//Layer//Shape[shape_type/@value='TEXT']/outline_peninfo/Width/@value", "ele": "//Layer//Shape[shape_type/@value='TEXT']/outline_peninfo/Width/@value",
"value": "5", "value": "5",
"point": 3 "point": 3
@@ -626,19 +632,20 @@
"desc": "색상 코드 비교 시 소문자로 입력할 것" "desc": "색상 코드 비교 시 소문자로 입력할 것"
}, },
"15": { "15": {
"type": "boolean",
"ele": "//Layer[MaskOpType/@value='Clipping'][last()]", "ele": "//Layer[MaskOpType/@value='Clipping'][last()]",
"point": 6, "point": 6,
"desc": "클리핑 마스크 항목은 별도 레이어로 추가되고 해당 속성을 추가해놓은 레이어가 있는지 여부 체크 함" "desc": "클리핑 마스크 항목은 별도 레이어로 추가되고 해당 속성을 추가해놓은 레이어가 있는지 여부 체크 함"
}, },
"16": { "16": {
"ele": "//Layer[contains(Name/@value, 'Layer 5')]//shape_type/@value", "type": "exists",
"ele": "//Layer/Shapes/Shape/shape_type/@value",
"value": "ELLIPSE", "value": "ELLIPSE",
"point": 3 "point": 3
}, },
"17": { "17": {
"type": "size", "type": "size",
"posX": "//Layer[contains(Name/@value, 'Layer 5')]//op_points[Item]/Item[last()]/X/@value - //Layer[contains(Name/@value, 'Layer 5')]//op_points[Item]/Item[1]/X/@value", "ele": "//Layer//op_points",
"posY": "//Layer[contains(Name/@value, 'Layer 5')]//op_points[Item]/Item[last()]/Y/@value - //Layer[contains(Name/@value, 'Layer 5')]//op_points[Item]/Item[1]/Y/@value",
"value": { "value": {
"width": 150, "width": 150,
"height": 150 "height": 150
@@ -647,13 +654,14 @@
"desc": "레이어 쉐이프 X, Y 좌표를 가지고 너비, 높이 계산하여 정답 채점" "desc": "레이어 쉐이프 X, Y 좌표를 가지고 너비, 높이 계산하여 정답 채점"
}, },
"18": { "18": {
"ele": "//Layer[contains(Name/@value, 'Layer 5')]//outline_peninfo/Width/@value", "type": "exists",
"ele": "//Layer//outline_peninfo/Width/@value",
"value": "3", "value": "3",
"point": 3 "point": 3
}, },
"19": { "19": {
"type": "color", "type": "color",
"ele": "//Layer//Shape[shape_type/@value='RECTANGLE'][contains(draw_type/@value, 'Outline')]/primary_color/@value", "ele": "//Layer//Shape[contains(draw_type/@value, 'Outline')]/primary_color/@value",
"value": "40EEAB", "value": "40EEAB",
"point": 3, "point": 3,
"desc": "색상 코드 비교 시 소문자로 입력할 것(채우기:secondary_color, 외곽선:primary_color)" "desc": "색상 코드 비교 시 소문자로 입력할 것(채우기:secondary_color, 외곽선:primary_color)"
@@ -661,11 +669,11 @@
"20": { "20": {
"type": "shadow", "type": "shadow",
"ele": { "ele": {
"shadow": "//Layer//Shape[shape_type/@value='RECTANGLE'][contains(draw_type/@value, 'Shadow')]", "shadow": "//Layer//Shape[contains(draw_type/@value, 'Shadow')]",
"width": "//Layer//Shape[shape_type/@value='RECTANGLE'][contains(draw_type/@value, 'Shadow')]/shadow_width/@value", "width": "//Layer//Shape[contains(draw_type/@value, 'Shadow')]/shadow_width/@value",
"distance": "//Layer//Shape[shape_type/@value='RECTANGLE'][contains(draw_type/@value, 'Shadow')]/shadow_distance/@value", "distance": "//Layer//Shape[contains(draw_type/@value, 'Shadow')]/shadow_distance/@value",
"blur": "//Layer//Shape[shape_type/@value='RECTANGLE'][contains(draw_type/@value, 'Shadow')]/shadow_blur/@value", "blur": "//Layer//Shape[contains(draw_type/@value, 'Shadow')]/shadow_blur/@value",
"angle": "//Layer//Shape[shape_type/@value='RECTANGLE'][contains(draw_type/@value, 'Shadow')]/shadow_angle/@value" "angle": "//Layer//Shape[contains(draw_type/@value, 'Shadow')]/shadow_angle/@value"
}, },
"value": { "value": {
"width": "5", "width": "5",

View File

@@ -97,9 +97,11 @@ function getGpdpScore(gpdpData, scoringJson, index) {
const layer = scoringData[key].layer; const layer = scoringData[key].layer;
const option = scoringData[key].option; const option = scoringData[key].option;
const style = scoringData[key].style;
ele = typeof ele === 'string' ? ele.replace(/{layer}/g, layer) : ele; ele = typeof ele === 'string' ? ele.replace(/{layer}/g, layer) : ele;
ele = typeof ele === 'string' ? ele.replace(/{option}/g, option) : ele; ele = typeof ele === 'string' ? ele.replace(/{option}/g, option) : ele;
ele = typeof ele === 'string' ? ele.replace(/{style}/g, style) : ele;
if (search !== undefined) { if (search !== undefined) {
let result = findSimilarString(gpdpXmlDoc, search, 0.8) let result = findSimilarString(gpdpXmlDoc, search, 0.8)
@@ -138,13 +140,26 @@ function getGpdpScore(gpdpData, scoringJson, index) {
// } // }
// }); // });
// } // }
if (type == "boolean") {
const items = xpath.select(ele, gpdpXmlDoc);
// xpath 결과값을 반환하는 요소가 있을 경우
if (items) {
totalScore += point;
scoringResult[key] = point;
console.log("✅ 찾는 요소 존재함");
}
else {
scoringResult[key] = 0;
console.log("❌ 찾는 요소 없음");
}
}
// 이펙트 효과의 이름과 속성값을 비교 // 이펙트 효과의 이름과 속성값을 비교
if (type == "effects") { else if (type == "effects") {
const items = xpath.select(ele, gpdpXmlDoc); const items = xpath.select(ele, gpdpXmlDoc);
let matched = false; let matched = false;
// 각 Item 요소별 이름과 속성값을 구하고 정답과 비교 // 각 Item 요소별 이름과 속성값을 구하고 정답과 비교
for (const item of items) { for (const item of items) {
const name = xpath.select1('Name/@value', item)?.value; const name = xpath.select1('Name/@value', item)?.value;
@@ -198,13 +213,13 @@ function getGpdpScore(gpdpData, scoringJson, index) {
} }
} }
} }
else if (type == "isExist") { else if (type == "exists") {
const result = xpath.select(ele, gpdpXmlDoc); const result = xpath.select(ele, gpdpXmlDoc);
const isMatch = result.some(v => { const isMatch = result.some(v => {
if (v.value === rightAnswer) { if (v.value === rightAnswer) {
totalScore += point; totalScore += point;
scoringResult[key] = point; scoringResult[key] = point;
console.log("🚀 ~ result.forEach ~ 정답 일치:", rightAnswer) console.log(`✅ 정답 일치 > [작성답안]:${v.value} [정답]:${rightAnswer}`);
return true; return true;
} }
return false; return false;
@@ -212,7 +227,7 @@ function getGpdpScore(gpdpData, scoringJson, index) {
if (!isMatch) { if (!isMatch) {
scoringResult[key] = 0; scoringResult[key] = 0;
console.log("🚀 ~ result.forEach ~ 오답:", rightAnswer) console.log(`❌ 정답 없음 > [정답]:${rightAnswer}`);
} }
} }
@@ -231,24 +246,29 @@ function getGpdpScore(gpdpData, scoringJson, index) {
console.log('ele not matched, ' + result[0].value); console.log('ele not matched, ' + result[0].value);
} }
} }
else if (type == "color") {
let result = xpath.select(ele, gpdpXmlDoc);
if (result.length == 0) {
scoringResult[key] = 0;
console.log('ele not found');
continue;
}
const hexColor = parseColorToHex(result[0].value);
if (hexColor === rightAnswer) { else if (type === "color") {
totalScore += point; const items = xpath.select(ele, gpdpXmlDoc);
scoringResult[key] = point; let matched = false;
console.log('color matched, ' + hexColor);
} else { for (const item of items) {
const color = parseColorToHex(item.value);
// console.log("🚀 ~ getGpdpScore ~ color:", color);
// console.log("🚀 ~ getGpdpScore ~ rightColor:", rightAnswer);
if (color === rightAnswer) {
totalScore += point;
scoringResult[key] = point;
matched = true;
console.log(`✅ 정답 일치 > [작성답안]:${color} [정답]:${rightAnswer}`);
break;
}
}
if (!matched) {
scoringResult[key] = 0; scoringResult[key] = 0;
console.log('color not matched, ' + hexColor); console.log(`❌ 정답 없음 > [정답]:${rightAnswer}`);
} }
} }
else if (type == "multi") { else if (type == "multi") {
try { try {
const result = xpath.select(ele, gpdpXmlDoc); const result = xpath.select(ele, gpdpXmlDoc);
@@ -308,7 +328,7 @@ function getGpdpScore(gpdpData, scoringJson, index) {
const width = Math.round(Math.abs(x2 - x1)); const width = Math.round(Math.abs(x2 - x1));
const height = Math.round(Math.abs(y2 - y1)); const height = Math.round(Math.abs(y2 - y1));
if ( width === rightAnswer["width"] && height === rightAnswer["height"]) { if (width === rightAnswer["width"] && height === rightAnswer["height"]) {
totalScore += point; totalScore += point;
scoringResult[key] = point; scoringResult[key] = point;
matched = true; matched = true;
@@ -327,13 +347,13 @@ function getGpdpScore(gpdpData, scoringJson, index) {
const endColorXpath = scoringData[key].endColor; const endColorXpath = scoringData[key].endColor;
let matched = false; let matched = false;
for ( const item of items) { for (const item of items) {
const startColor = parseColorToHex(xpath.select1(startColorXpath, item)?.value); const startColor = parseColorToHex(xpath.select1(startColorXpath, item)?.value);
const endColor = parseColorToHex(xpath.select1(endColorXpath, item)?.value); const endColor = parseColorToHex(xpath.select1(endColorXpath, item)?.value);
console.log(startColor + ":" + rightAnswer["startColor"], endColor + ":" + rightAnswer["endColor"]); console.log(startColor + ":" + rightAnswer["startColor"], endColor + ":" + rightAnswer["endColor"]);
if ( startColor === rightAnswer["startColor"] && endColor === rightAnswer["endColor"]) { if (startColor === rightAnswer["startColor"] && endColor === rightAnswer["endColor"]) {
totalScore += point; totalScore += point;
scoringResult[key] = point; scoringResult[key] = point;
matched = true; matched = true;

View File

@@ -1 +1 @@
[{"kind":2,"language":"xpath","value":"//Layer[Name[@value='Tracking']]/Effects/Item/Name/@value"},{"kind":2,"language":"xpath","value":"//Layer/Shapes/Shape[*[starts-with(name(), 'gradient')]]"},{"kind":2,"language":"xpath","value":"//Layer/Shapes/Shape"}] [{"kind":2,"language":"xpath","value":"//Layer[Name[@value='Tracking']]/Effects/Item/Name/@value"},{"kind":2,"language":"xpath","value":"//Layer/Shapes/Shape[*[starts-with(name(), 'gradient')]]"},{"kind":2,"language":"xpath","value":"//Layer/Shapes/Shape/shape_type/@value"}]