{"id":1815,"date":"2026-08-29T08:52:56","date_gmt":"2026-08-29T00:52:56","guid":{"rendered":"https:\/\/blog.guguan.us.kg\/?p=1815"},"modified":"2026-08-29T09:00:10","modified_gmt":"2026-08-29T01:00:10","slug":"%e6%98%9f%e9%9c%b2%e8%b0%b7%e5%ad%98%e6%a1%a3%e6%8a%80%e8%83%bd%e4%bf%ae%e6%94%b9%e5%b7%a5%e5%85%b7","status":"publish","type":"post","link":"https:\/\/blog.guguan.us.kg\/?p=1815","title":{"rendered":"\u661f\u9732\u8c37\u5b58\u6863\u6280\u80fd\u4fee\u6539\u5de5\u5177"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">\u4e0a\u4f20\u5b58\u6863\u7684\u4e3bXML\u6587\u4ef6\u5373\u53ef\u4fee\u6539\u73a9\u5bb6\u804c\u4e1a\u7b49\u7ea7<\/p>\n\n\n\n<script data-wp-block-html=\"js\">\nlet globalXmlDoc = null;\nlet originalFileName = \"SaveGameInfo\";\n\nconst skillNames = [\n\t{ key: 'farmingLevel', expIndex: 0, label: '\u8015\u79cd' },\n\t{ key: 'fishingLevel', expIndex: 1, label: '\u9493\u9c7c' },\n\t{ key: 'foragingLevel', expIndex: 2, label: '\u91c7\u96c6' },\n\t{ key: 'miningLevel', expIndex: 3, label: '\u91c7\u77ff' },\n\t{ key: 'combatLevel', expIndex: 4, label: '\u6218\u6597' },\n\t{ key: 'luckLevel', expIndex: 5, label: '\u5e78\u8fd0' }\n];\n\ndocument.addEventListener('DOMContentLoaded', function() {\n\tdocument.getElementById('stardewFileInput').addEventListener('change', function(e) {\n\t\tconst file = e.target.files[0];\n\t\tif (!file) return;\n\t\toriginalFileName = file.name;\n\n\t\tconst reader = new FileReader();\n\t\treader.onload = function(evt) {\n\t\t\tconst xmlText = evt.target.result;\n\t\t\tconst parser = new DOMParser();\n\t\t\tglobalXmlDoc = parser.parseFromString(xmlText, \"text\/xml\");\n\n\t\t\tconst characters = parseSaveData(globalXmlDoc);\n\t\t\trenderStardewUI(characters);\n\t\t\tdocument.getElementById('stardewDownloadBtn').hidden = false;\n\t\t};\n\t\treader.readAsText(file);\n\t});\n});\n\nfunction parseSaveData(xmlDoc) {\n\tconst list = [];\n\n\t\/\/ \u73a9\u5bb6 (SaveGame -> player)\n\tconst playerNode = xmlDoc.querySelector(\"SaveGame > player\");\n\tif (playerNode) {\n\t\tlist.push(extractFarmerData(playerNode, \"\u73a9\u5bb6\", \"player\"));\n\t}\n\n\t\/\/ \u5176\u4ed6\u519c\u6c11 (SaveGame -> farmhands -> Farmer)\n\tconst farmhands = xmlDoc.querySelectorAll(\"SaveGame > farmhands > Farmer\");\n\tfarmhands.forEach((fhNode, index) => {\n\t\tconst nameNode = fhNode.querySelector(\"name\");\n\t\tconst name = nameNode ? nameNode.textContent : `\u519c\u6c11 #${index + 1}`;\n\t\tlist.push(extractFarmerData(fhNode, `\u519c\u6c11`, `farmhand_${index}`));\n\t});\n\n\treturn list;\n}\n\nfunction extractFarmerData(node, title, id) {\n\tconst nameNode = node.querySelector(\"name\");\n\tconst charName = nameNode ? nameNode.textContent : \"\u672a\u547d\u540d\u7684\u519c\u6c11\";\n\n\tconst levels = {};\n\t['farmingLevel', 'miningLevel', 'combatLevel', 'foragingLevel', 'fishingLevel', 'luckLevel'].forEach(lvl => {\n\t\tconst tag = node.querySelector(lvl);\n\t\tlevels[lvl] = tag ? parseInt(tag.textContent) || 0 : 0;\n\t});\n\n\tconst expInts = node.querySelectorAll(\"experiencePoints > int\");\n\tconst exps = Array.from(expInts).map(i => parseInt(i.textContent) || 0);\n\n\treturn {\n\t\tid: id,\n\t\ttitle: title,\n\t\tname: charName,\n\t\tdomNode: node,\n\t\tlevels: levels,\n\t\texps: exps\n\t};\n}\n\nfunction renderStardewUI(characters) {\n\tconst container = document.getElementById('stardewEditorContainer');\n\tcontainer.innerHTML = '';\n\n\tcharacters.forEach((char) => {\n\t\tconst details = document.createElement('details');\n\t\tdetails.open = true; \/\/ \u9ed8\u8ba4\u5c55\u5f00\n\t\tdetails.id = `stardew_card_${char.id}`;\n\t\tdetails.domRef = char.domNode;\n\n\t\tconst summary = document.createElement('summary');\n\t\tsummary.innerHTML = `<strong>${char.title}: ${char.name}<\/strong>`;\n\t\tdetails.appendChild(summary);\n\n\t\tconst table = document.createElement('table');\n\t\ttable.border = \"1\";\n\n\t\tlet tableContent = `\n\t\t\t<thead>\n\t\t\t\t<tr>\n\t\t\t\t\t<th>\u6280\u80fd<\/th>\n\t\t\t\t\t<th>\u7b49\u7ea7 (Level)<\/th>\n\t\t\t\t\t<th>\u7ecf\u9a8c\u503c (Experience)<\/th>\n\t\t\t\t<\/tr>\n\t\t\t<\/thead>\n\t\t\t<tbody>\n\t\t`;\n\n\t\tskillNames.forEach(skill => {\n\t\t\tconst currentLvl = char.levels[skill.key] || 0;\n\t\t\tconst currentExp = char.exps[skill.expIndex] || 0;\n\n\t\t\ttableContent += `\n\t\t\t\t<tr>\n\t\t\t\t\t<td><strong>${skill.label}<\/strong><\/td>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<input type=\"number\" value=\"${currentLvl}\" min=\"0\" onchange=\"updateStardewDOM(this, '${char.id}', '${skill.key}', 'level')\">\n\t\t\t\t\t<\/td>\n\t\t\t\t\t<td>\n\t\t\t\t\t\t<input type=\"number\" value=\"${currentExp}\" min=\"0\" onchange=\"updateStardewDOM(this, '${char.id}', ${skill.expIndex}, 'exp')\">\n\t\t\t\t\t<\/td>\n\t\t\t\t<\/tr>\n\t\t\t`;\n\t\t});\n\n\t\ttableContent += `<\/tbody>`;\n\t\ttable.innerHTML = tableContent;\n\n\t\tdetails.appendChild(table);\n\t\tdetails.appendChild(document.createElement('br'));\n\t\tcontainer.appendChild(details);\n\t});\n}\n\nfunction updateStardewDOM(input, charId, keyOrIndex, type) {\n\tconst card = document.getElementById(`stardew_card_${charId}`);\n\tconst domNode = card.domRef;\n\tconst val = input.value;\n\n\tif (type === 'level') {\n\t\tlet tag = domNode.querySelector(keyOrIndex);\n\t\tif (!tag) {\n\t\t\ttag = globalXmlDoc.createElement(keyOrIndex);\n\t\t\tdomNode.appendChild(tag);\n\t\t}\n\t\ttag.textContent = val;\n\t} else if (type === 'exp') {\n\t\tconst expInts = domNode.querySelectorAll(\"experiencePoints > int\");\n\t\tif (expInts[keyOrIndex]) {\n\t\t\texpInts[keyOrIndex].textContent = val;\n\t\t}\n\t}\n}\n\nfunction exportStardewXML() {\n\tif (!globalXmlDoc) return;\n\n\tconst serializer = new XMLSerializer();\n\tconst xmlString = serializer.serializeToString(globalXmlDoc);\n\n\tconst blob = new Blob([xmlString], { type: \"application\/xml\" });\n\tconst link = document.createElement(\"a\");\n\tlink.href = URL.createObjectURL(blob);\n\tlink.download = originalFileName;\n\tlink.click();\n\tURL.revokeObjectURL(link.href);\n}\n<\/script>\n\n<section>\n\t<fieldset>\n\t\t<p>\n\t\t<legend>\u4e0a\u4f20\u5b58\u6863<\/legend>\n\t\t<label for=\"stardewFileInput\">\u9009\u62e9\u6587\u4ef6\uff1a<\/label>\n\t\t<input type=\"file\" id=\"stardewFileInput\" accept=\"*\">\n\t\t<button type=\"button\" id=\"stardewDownloadBtn\" hidden=\"\" onclick=\"exportStardewXML()\">\u5bfc\u51fa\u4fee\u6539\u540e\u7684\u5b58\u6863<\/button>\n\t\t<\/p>\n\t<\/fieldset>\n<\/section>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><\/p><section id=\"stardewEditorContainer\"><i>\u8bf7\u5148\u4e0a\u4f20\u5b58\u6863\u6587\u4ef6<\/i><\/section><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u4e00\u4e2a\u7b80\u5355\u7684\u661f\u9732\u8c37\u7269\u8bed\u5b58\u6863\u4fee\u6539\u5668\uff0c\u7528\u4e8e\u4fee\u6539\u73a9\u5bb6\u804c\u4e1a\u7b49\u7ea7<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[144],"class_list":["post-1815","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-144"],"_links":{"self":[{"href":"https:\/\/blog.guguan.us.kg\/index.php?rest_route=\/wp\/v2\/posts\/1815","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.guguan.us.kg\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.guguan.us.kg\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.guguan.us.kg\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.guguan.us.kg\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1815"}],"version-history":[{"count":6,"href":"https:\/\/blog.guguan.us.kg\/index.php?rest_route=\/wp\/v2\/posts\/1815\/revisions"}],"predecessor-version":[{"id":1821,"href":"https:\/\/blog.guguan.us.kg\/index.php?rest_route=\/wp\/v2\/posts\/1815\/revisions\/1821"}],"wp:attachment":[{"href":"https:\/\/blog.guguan.us.kg\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1815"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.guguan.us.kg\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1815"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.guguan.us.kg\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1815"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}