Как получить глубоко вложенную объектную структуру из массива значений с помощью Javascript - PullRequest
4 голосов
/ 06 октября 2019

У меня есть JSON, представляющий некоторый контент в текстовом редакторе. Вот пример:

{ "type": "doc", "content": [ { "type": "paragraph", "content": [ { "type": "text", "marks": [ { "type": "bold" } ], "text": "Testing" }, { "type": "text", "text": " " }, { "type": "text", "marks": [ { "type": "strike" } ], "text": "Testing " }, { "type": "text", "marks": [ { "type": "strike" }, { "type": "underline" } ], "text": "Testing" }, { "type": "text", "marks": [ { "type": "strike" } ], "text": " Testing" } ] }, { "type": "paragraph" }, { "type": "paragraph", "content": [ { "type": "text", "marks": [ { "type": "bold" } ], "text": "Testing " }, { "type": "text", "marks": [ { "type": "bold" }, { "type": "italic" }, { "type": "strike" } ], "text": "Testing" }, { "type": "text", "marks": [ { "type": "bold" } ], "text": " Testing" } ] }, { "type": "paragraph" } ] }

Это хорошо, потому что я могу смело превращать его в html, однако вместо вложенных значений для стилей он представляет этот стиль в подмассиве marks. Что бы я предпочел, если бы хранить данные, уже вложенные в отношении их естественной иерархии.

Таким образом, вместо:

{ 
     "type":"text",
     "marks": [{ "type": "bold" }, { "type": "italic" }],
     "text": "Testing"
}

Я хотел бы иметь что-то, что более точно представляет результирующий результатHTML:

{
  "type" : "bold", 
   "content" : [{ 
       "type" : "italic", 
       "content":[{ 
            "type" : "text", 
            "text" : "Testing"
       }]
   }]
}

Я пробовал различные способы синтаксического анализа json и его сохранения, как показано ниже, но я думаю, что мне не хватает некоторых фундаментальных принципов работы javascript с объектами, потому что изменения не происходятmade.

Я сделал различные итерации нижеприведенной функции для каждого массива marks в json.

item = {type:type, text:text}

marks.forEach((mark)=>{
   let newObj = {content:[], type:mark.type}
    item = newObj.content.push(item)
});

Некоторая дополнительная справочная информация, это json, сгенерированныйПодсказка wysiwyg редактор, который основан на prosemirror. Я не могу использовать обычный экспорт HTML, потому что я делаю специальные вещи с данными. Любая помощь будет принята с благодарностью.

РЕДАКТИРОВАТЬ: Дакр Денни предложил ответ, используя reduceRight(), который ответил на первую часть проблемы. Тем не менее, функция ниже все еще возвращает исходный объект без изменений.

   const content = editorContent.content

    function parseContent (arr) {
      arr.forEach((item)=>{

        // Check if item contains another array of items, and then iterate
        over that one too.

        if(item.content){
          parseContent(item.content)
        }

        if(item.marks){
          //Extract values from item

          // THis is the correct function
          const processContent = ({ marks, text }) =>
          marks.reduceRight((acc, mark) => ({ type: mark.type, content: [acc]
            }), {
              type: "text",
              text: text
            });

          item = processContent({ text:item.text, marks:item.marks })


        }
      })
    }

    parseContent(content)

return content
//

1 Ответ

2 голосов
/ 07 октября 2019

Одной из возможностей было бы использование reduceRight для «сокращения» подмассива marks вашего входного содержимого до одного объекта с требуемой «вложенной структурой».

Идея состоит в том, чтобы начать сокращение с объекта { type : "text", text : content.text } (который будет вложенным), а затем постепенно "обернуть" этот объект объектами, содержащими данные типа.

Чтобы добиться правильного порядка «обтекания» для объектов с метаданными типа, массив marks необходимо уменьшить в обратном порядке. Вот почему используется reduceRight (а не обычный reduce).

Вот пример фрагмента, демонстрирующий эту идею в действии:

/* Helper function processes the content object, returns the required
nested structure */
const processContent = ({ marks, text }) => 
    marks.reduceRight((acc, mark) => ({ type: mark.type, content: [acc] 
}), {
  type: "text",
  text: text
});

console.log(processContent({
  "type": "text",
  "marks": [{
    "type": "bold"
  }, {
    "type": "italic"
  }],
  "text": "Testing"
}))

/*
Result:
{
  "type" : "bold", 
   "content" : [{ 
       "type" : "italic", 
       "content":[{ 
            "type" : "text", 
            "text" : "Testing"
       }]
   }]
}
*/

Надеюсь, это поможет!

...