我有一个XML字符串,如下所示:
'<ALEXA VER="0.9" URL="davidwalsh.name/" HOME="0" AID="="><SD TITLE="A" FLAGS="" HOST="davidwalsh.name"><TITLE TEXT="David Walsh Blog :: PHP, MySQL, CSS, Javascript, MooTools, and Everything Else"/><LINKSIN NUM="1102"/><SPEED TEXT="1421" PCT="51"/></SD><SD><POPULARITY URL="davidwalsh.name/" TEXT="7131"/><REACH RANK="5952"/><RANK DELTA="-1648"/></SD></ALEXA>'
我想把它转换成JSON格式:
{
"ALEXA":{
"@attributes":{
"VER":"0.9",
"URL":"davidwalsh.name/",
"HOME":"0",
"AID":"="
},
"SD":[
{
"@attributes":{
"TITLE":"A",
"FLAGS":"",
"HOST":"davidwalsh.name"
},
"TITLE":{
"@attributes":{
"TEXT":"David Walsh Blog :: PHP, MySQL, CSS, Javascript, MooTools, and Everything Else"
}
...我已经找到了很多针对js的解决方案,但它们都不适用于google-apps-script。我还看到了这样一个问题:Parsing XML on a Google Apps script,但它并不完全符合我的情况:我喜欢将任何XML解析成JSON,而不仅仅是提供的示例。我已经找到了自己的解决方案(在答案中),但不确定它是否适合所有情况。
发布于 2020-03-16 23:21:33
我认为解决方案应该是一个递归函数。经过一些研究,我找到了David Walsh的this great code,并且能够采用它。这就是我要说的:
// Changes XML to JSON
// Original code: https://davidwalsh.name/convert-xml-json
function xmlToJson_(xml) {
// Create the return object
var obj = {};
// get type
var type = '';
try { type = xml.getType(); } catch(e){}
if (type == 'ELEMENT') {
// do attributes
var attributes = xml.getAttributes();
if (attributes.length > 0) {
obj["@attributes"] = {};
for (var j = 0; j < attributes.length; j++) {
var attribute = attributes[j];
obj["@attributes"][attribute.getName()] = attribute.getValue();
}
}
} else if (type == 'TEXT') {
obj = xml.getValue();
}
// get children
var elements = [];
try { elements = xml.getAllContent(); } catch(e){}
// do children
if (elements.length > 0) {
for(var i = 0; i < elements.length; i++) {
var item = elements[i];
var nodeName = false;
try { nodeName = item.getName(); } catch(e){}
if (nodeName)
{
if (typeof(obj[nodeName]) == "undefined") {
obj[nodeName] = xmlToJson_(item);
} else {
if (typeof(obj[nodeName].push) == "undefined") {
var old = obj[nodeName];
obj[nodeName] = [];
obj[nodeName].push(old);
}
obj[nodeName].push(xmlToJson_(item));
}
}
}
}
return obj;
};我已经发布了示例on GitHub。
用法:
var xml = XmlService.parse(xmltext);
Logger.log(JSON.stringify(xmlToJson_(xml)));参考资料:
发布于 2021-12-20 22:34:50
最初的答案对我不起作用。应用程序脚本XML API中可能有更改,但它不会包含没有子节点的文本内容。下面是我写的代码,看起来运行得很好。
请注意,它的输出方式与您提供的示例略有不同。我发现对于更广泛的用例,这可能是一种更一致的格式。我还发现,我所做的每件事都没有必要包含属性,这造成了混乱,所以我添加了一个不解析属性的版本。
如果包含属性,则输出遵循以下模式:
{foo:{attributes:{...},content:{...}}要包括属性:
function xmlParse(element) {
/*
* Takes an XML element and returns an object containing its children or text
* If children are present, recursively calls xmlTest() on them
*
* If multiple children share a name, they are added as objects in an array
* If children have unique names, they are simply added as keys
* i.e.
* <foo><bar>one</bar><baz>two</baz></foo> === {foo: {bar: 'one', baz: 'two'}}
* <foo><bar>one</bar><bar>two</bar></foo> === {foo: [{bar: 'one'},{bar: 'two'}]}
*/
let obj = {}
const rootName = element.getName();
// Parse attributes
const attributes = element.getAttributes();
const attributesObj = {};
for(const attribute of attributes) {
attributesObj[attribute.getName()] = attribute.getValue();
}
obj[rootName] = {
attributes: attributesObj,
content: {}
}
const children = element.getChildren();
const childNames = children.map(child => child.getName());
if (children.length === 0) {
// Base case - get text content if no children
obj = {
content: element.getText(),
attributes: attributesObj
}
} else if (new Set(childNames).size !== childNames.length) {
// If nonunique child names, add children as an array
obj[rootName].content = [];
for (const child of children) {
if (child.getChildren().length === 0) {
const childObj = {};
childObj[child.getName()] = xmlParse(child);
obj[rootName].content.push(childObj)
} else {
const childObj = xmlParse(child);
obj[rootName].content.push(childObj)
}
}
} else {
// If unique child names, add children as keys
obj[rootName].content = {};
for (const child of children) {
if (child.getChildren().length === 0) {
obj[rootName].content[child.getName()] = xmlParse(child);
} else {
obj[rootName].content = xmlParse(child);
}
}
}
return obj;
}不带属性:
function xmlParse(element) {
/*
* Takes an XML element and returns an object containing its children or text
* If children are present, recursively calls xmlTest() on them
*
* If multiple children share a name, they are added as objects in an array
* If children have unique names, they are simply added as keys
* i.e.
* <foo><bar>one</bar><baz>two</baz></foo> === {foo: {bar: 'one', baz: 'two'}}
* <foo><bar>one</bar><bar>two</bar></foo> === {foo: [{bar: 'one'},{bar: 'two'}]}
*/
let obj = {}
const rootName = element.getName();
const children = element.getChildren();
const childNames = children.map(child => child.getName());
if (children.length === 0) {
// Base case - get text content if no children
obj = element.getText();
} else if (new Set(childNames).size !== childNames.length) {
// If nonunique child names, add children as an array
obj[rootName] = [];
for (const child of children) {
if (child.getChildren().length === 0) {
const childObj = {};
childObj[child.getName()] = xmlParse(child);
obj[rootName].push(childObj)
} else {
const childObj = xmlParse(child);
obj[rootName].push(childObj)
}
}
} else {
// If unique child names, add children as keys
obj[rootName] = {};
for (const child of children) {
if (child.getChildren().length === 0) {
obj[rootName][child.getName()] = xmlParse(child);
} else {
obj[rootName] = xmlParse(child);
}
}
}
return obj;
}这两种方法的用法:
const xml = XmlService.parse(xmlText);
const rootElement = xml.getRootElement();
const obj = xmlParse(rootElement);
const asJson = JSON.stringify(obj);参考资料:
https://stackoverflow.com/questions/60708652
复制相似问题