Javascript 将任意大小的列表解析为类似XML的字符串

Javascript 将任意大小的列表解析为类似XML的字符串,javascript,recursion,ecmascript-6,stack,logic,Javascript,Recursion,Ecmascript 6,Stack,Logic,我有一个排列如下的数组: let example_arr = [ "backend", [ "#host#www.example.com", "#port#80" ], "endpoints", [ "endpoint", [ "#external#/foo/bar/cat/mom

我有一个排列如下的数组:

let example_arr = 
    [
        "backend",
        [
            "#host#www.example.com",
            "#port#80"
        ],
        "endpoints",
        [
            "endpoint",
            [
                "#external#/foo/bar/cat/mom/",
                "#internal#/banana/",
                "params",
                [
                    "param",
                    [
                        "#sourceValue#acis.usermove.md"
                    ]
                ]
            ],
        ]
    ];
此数组需要解析为如下所示的字符串:

"
<backend host="www.example.com" port="80" />
<endpoints>
    <endpoint external="/foo/bar/cat/mom/" internal="/banana/"/>
        <params>
            <param sourceValue="acis.usermove.md" />
        </params>
    </endpoint>
</endpoints>
"
”
"
我研究这个问题已经有一段时间了,但已经放弃了一次又一次的尝试。以下是我的最新尝试:

let str_answer = helper_string_builder(example_arr, 3);

function helper_string_builder(xml_list_data, depth) {
    let string_builder = "";
    for (let i = 0; i < xml_list_data.length; i++) {
        if (Array.isArray(xml_list_data[i]) !== true) {
            if (xml_list_data[i].charAt(0) !== "#" && xml_list_data[i].length > 1) {

                if(typeof xml_list_data[i + 1] === "undefined"){
                    continue;
                }

                string_builder += " ".repeat(depth) + "<" + xml_list_data[i] + ">\n";

                for (let j = 0; j < xml_list_data[i + 1].length; j++) {
                    if (j === 0) {
                        string_builder += " ".repeat(depth + 3)
                    }
                    string_builder +=
                        value_reader("name", xml_list_data[i + 1][j]) +
                        "=\"" +
                        value_reader("content", xml_list_data[i + 1][j]) +
                        "\" ";
                }

                string_builder += "\n" + " ".repeat(depth) + "</" + xml_list_data[i] + ">\n";

            }
            console.log(string_builder);
        } else {
            string_builder += helper_string_builder(xml_list_data[i], depth + 3);
        }
    }
    return string_builder;
}


function value_reader(mode, str) {
    str = str + '';
    if (str.substring(0, 1) != '#') {
        return 'ERROR';
    }
    if (mode === "name") {
        let start_pos = str.indexOf('#') + 1;
        let end_pos = str.indexOf('#', start_pos);
        let name_cutout = str.substring(start_pos, end_pos);
        return name_cutout;
    } else if (mode === "content") {
        let start_pos = str.indexOf('#') + 1;
        let end_pos = str.indexOf('#', start_pos);
        let content_cutout = str.substring(end_pos + 1);
        return content_cutout;
    } else {
        throw new Error("Valid \'mode\' not passed in");
    }
}
let str\u answer=helper\u string\u builder(示例3);
函数助手\u字符串\u生成器(xml\u列表\u数据,深度){
让字符串_builder=“”;
for(设i=0;i1){
if(xml列表数据类型[i+1]=“未定义”){
继续;
}
字符串生成器+=“”。重复(深度)+“\n”;
for(设j=0;j

不知道如何继续解决这个问题,我想知道是否有人可以帮助我。谢谢

您的输入格式非常复杂,因此我想我的主要建议是在树中遍历两次:

  • 首先,创建一个易于使用的
    元素
    对象树:每个对象都有一个
    标记名
    属性、一个
    属性
    数组和一个
    子对象
    数组。
    • 属性
      数组可以包含
      属性
      实例,它们是
      {key,value}
    • 子元素
      数组可以包含
      元素
      实例
  • 然后,在树上循环并为每个
    元素返回字符串
  • 重新格式化数据 代码有点混乱,但我(认为我)重用了您的大部分逻辑:

    • 如果它是一个字符串,并且以
      “#”
      开头,那么它就是一个属性
    • 如果它是字符串而不是属性,则它是一个新的
      元素
    • 如果是数组,则该数组包含先前生成的
      元素的内容
    //递归创建包含属性和子元素的元素树
    常量分区=xs=>xs.reduce(
    ([lastPart,…parts],x)=>{
    开关(getType(x)){
    案例要素:
    返回[
    元素(x),
    …(最后一部分?[最后一部分]:[]),
    …零件
    ];
    案例阵列:
    常量attrsUntil=x.findIndex(Attribute.isNoAttribute);
    常量attrs=attrsUntil!=-1
    ?x.slice(0,attrsUntil)
    :x;
    const children=attrsUntil==-1
    ? []
    :x.slice(attrsUntil);
    返回[元素](
    lastPart.tagName,
    属性映射(Attribute.fromString),
    分区(儿童)
    ),…部分];
    违约:
    返回[最后一部分,…部分];
    }
    },
    []
    ).reverse()
    const getType=x=>
    数组。isArray(x)?排列
    :Attribute.isAttribute(x)?属性
    :元素;
    //一些实用新型和方法:
    常量属性=(键,值)=>
    ({key,value});
    Attribute.isAttribute=(str)=>
    str.charAt&&str.charAt(0)==“#”;
    Attribute.isNoAttribute=x=>!属性。isAttribute(x);
    Attribute.fromString=str=>Attribute(
    …str.split(“#”)切片(1)
    );
    常量元素=(标记名,属性=[],子元素=[])=>
    ({标记名,属性,子项});
    例如_arr=
    [
    “后端”,
    [
    “#主机#www.example.com”,
    “#端口#80”
    ],
    “端点”,
    [
    “端点”,
    [
    “#外部#/foo/bar/cat/mom/”,
    “#内部#/banana/”,
    “params”,
    [
    “param”,
    [
    “#sourceValue#acis.usermove.md”
    ]
    ]
    ],
    ]
    ];
    console.log(
    分区(示例_arr)
    
    );天哪。。。这太神奇了。我一直在努力解决这个问题,而我提出的实现仍然衍生出一些模糊的错误。将我的逻辑与你的逻辑交换,代码立即变得可跟踪,输出一致。向你致敬,用户3297291!