Преобразование XML в JSON с помощью рекурсии

На днях я придумал способ, с помощью которого можно легко преобразовать XML в объект JavaScript. Вот пример данных, которые я пытался прочитать.

Имейте в виду, что этот код использует WebAPI, поэтому он недоступен в javascript на стороне сервера, таком как NodeJS. Это отлично подходит для интерфейсных приложений, таких как React или Angular.

Формат XML обычно выглядит примерно так:

<book>
    <title>Some title</title>
    <description>some description </description>
    <author>
        <id>1</id>
        <name>some author name</name>
    </author>
    <review>nice book</review>
    <review>this book sucks</review>
    <review>amazing work</review>
</book>

Я хочу, чтобы вывод выглядел примерно так:

{
  "book": {
    "title": "Some title",
    "description": "some description",
    "author": { "id": "1", "name": "some author name" },
    "review": ["nice book", "this book sucks", "amazing work"]
  }
}

Поскольку XML имеет много вложенных тегов, эта проблема является примером практического применения рекурсии.

Прежде чем мы начнем писать код, нам нужно понять то, что называется DOMParser Web API.

Согласно документации MDN,

DOMParser – интерфейс, предоставляющий возможность синтаксического анализа XML или HTML исходного кода из строки в DOM дереве.

Проще говоря, он преобразует XML-строку в дерево DOM. Вот как это работает.

Допустим, у нас есть некоторый XML, хранящийся в строке, strxml. Мы можем проанализировать данные в нем как дерево DOM следующим образом:

let strxml = `<book><title>Some title</title>
<description>some description </description>
<author>
    <id>1</id>
    <name>some author name</name>
</author>
<review>nice book</review>
<review>this book sucks</review>
<review>amazing work</review></book>
`;

const parser = new DOMParser();  // initialize dom parser
const srcDOM = parser.parseFromString(strxml, "application/xml");  // convert dom string to dom tree. 

// Now we can call DOM methods like GetElementById, etc. on scrDOM. 

Теперь, когда у нас есть основы. Приступим к написанию кода.

Initialize variable jsonResult is empty object. 
If scrDOM has no children nodes:
    return innerHTML of the DOM. // This is our base case.

For each childNode in children nodes:
    Check if childNode has siblings of same name. 
    If it has no siblings of same name: 
        set childnode name as key whose value is json of the child node. (we're calling the function recursively.)
    If it has no siblings of same name
        set childnode name as key whose value is an empty array, every child whose name is same as this pushed into this array.
return jsonResult

Вот код JavaScript:

/**
 * This function coverts a DOM Tree into JavaScript Object. 
 * @param srcDOM: DOM Tree to be converted. 
 */
function xml2json(srcDOM) {
  let children = [...srcDOM.children];
  
  // base case for recursion. 
  if (!children.length) {
    return srcDOM.innerHTML
  }
  
  // initializing object to be returned. 
  let jsonResult = {};
  
  for (let child of children) {
    
    // checking is child has siblings of same name. 
    let childIsArray = children.filter(eachChild => eachChild.nodeName === child.nodeName).length > 1;

    // if child is array, save the values as array, else as strings. 
    if (childIsArray) {
      if (jsonResult[child.nodeName] === undefined) {
        jsonResult[child.nodeName] = [xml2json(child)];
      } else {
        jsonResult[child.nodeName].push(xml2json(child));
      }
    } else {
      jsonResult[child.nodeName] = xml2json(child);
    }
  }
  
  return jsonResult;
}

// testing the function
let xmlstr = `<book><title>Some title</title>
<description>some description </description>
<author>
    <id>1</id>
    <name>some author name</name>
</author>
<review>nice book</review>
<review>this book sucks</review>
<review>amazing work</review></book>
`;

// converting to DOM Tree
const parser = new DOMParser();
const srcDOM = parser.parseFromString(xmlstr, "application/xml");

// Converting DOM Tree To JSON. 
console.log(xml2json(srcDOM));

/** The output will be
{
  "book": {
    "title": "Some title",
    "description": "some description",
    "author": { "id": "1", "name": "some author name" },
    "review": ["nice book", "this book sucks", "amazing work"]
  }
}
*/

Это основной алгоритм / код для преобразования строки XML в объект JSON. Поскольку он использует рекурсию, он может очень глубоко проникать в дерево DOM и анализировать каждый отдельный элемент.

Это работает в большинстве случаев. Вы можете изменить этот алгоритм в соответствии со своими потребностями или требованиями.

Ответить