1

I'm using xml2js and trying to convert a Javascript object of this form:

{
  RootElement: {
    id: "1234",
    name: "Foo",
    children: [
      {
        id: "5678",
        name: "Bar",
        props: [
          {
            name: "Baz",
            code: "ABC"
          },
          {
            name: "Qux",
            code: "DEF"
          }
        ]
      }
    ]
  }  
}

into XML that looks like this:

<RootElement>
  <ns1:id xmlns:ns1="http://my.namespace">1234</ns1:id>
  <ns1:name xmlns:ns1="http://my.namespace">Foo</ns1:name>
  <ns1:children xmlns:ns1="http://my.namespace">
    <ns1:id>5678</ns1:id>
    <ns1:name>Bar</ns1:name>
    <ns1:props>
      <ns1:name>Baz</ns1:name>
      <ns1:code>ABC</ns1:code>
    </ns1:props>
    <ns1:props>
      <ns1:name>Qux</ns1:name>
      <ns1:code>DEF</ns1:code>
    </ns1:props>
  </ns1:children>
</RootElement>

It would make a lot more sense to me if the namespace was at the root element, but I'm in the process of trying to match an existing API and want every detail to be as close as possible to the current structure. Fixing that structure is a task for another day.

I can convert to intermediate JS structures to get it close to what's needed, but I am stuck when it comes to turning children: [ ... ] into <ns1:children xmlns:ns1="http://my.namespace"> ... </ns1:children>

If I create an intermediate format that looks like this:

{
    RootElement: {
        "ns1:id": {
            $: {
                "xmlns:ns1": "http://www.travelers.com/bi/els/document"
            },
            _: "1234"
        },
        "ns1:name": {
            $: {
                "xmlns:ns1": "http://www.travelers.com/bi/els/document"
            },
            _: "Foo"
        },
        "ns1:children": [
            {
                "ns1:id": "5678",
                "ns1:name": "Bar",
                "ns1:props": [
                    {
                        "ns1:code": "ABC",
                        "ns1:name": "Baz"
                    },
                    {
                        "ns1:code": "DEF",
                        "ns1:name": "Qux"
                    }
                ]
            },
            $: {
                "xmlns:ns1": "http://www.travelers.com/bi/els/document"
            }
        ]
    }
}

where the RootElement.children array has a property "$" with value {"xmlns:ns1": "http://www.travelers.com/bi/els/document"}

Then I generate something like this:

<RootElement>
  <ns1:id xmlns:ns1="http://my.namespace">1234</ns1:id>
  <ns1:name xmlns:ns1="http://my.namespace">Foo</ns1:name>
  <ns1:children>
    <ns1:id>5678</ns1:id>
    <ns1:name>Bar</ns1:name>
    <ns1:props>
      <ns1:name>Baz</ns1:name>
      <ns1:code>ABC</ns1:code>
    </ns1:props>
    <ns1:props>
      <ns1:name>Qux</ns1:name>
      <ns1:code>DEF</ns1:code>
    </ns1:props>
  </ns1:children>
  <ns1:children>  <!-- ***** oops ***** -->
    <xmlns:ns1>http://my.namespace</xmlns:ns1>
  </ns1:children>
</RootElement>

So instead of updating the children element to have a namespace, this simply adds an additional children element with that value.

I can't seem to run xml2js in a snippet, but it's running on RunKit.

Or I can make this intermediate format:

{
    "RootElement": {
        "ns1:id": {
            "$": {
                "xmlns:ns1": "http://my.namespace"
            },
            "_": "1234"
        },
        "ns1:name": {
            "$": {
                "xmlns:ns1": "http://my.namespace"
            },
            "_": "Foo"
        },
        "ns1:children": {
            "$": {
                "xmlns:ns1": "http://my.namespace"
            },
            "_": [
                {
                    "ns1:id": "5678",
                    "ns1:name": "Bar",
                    "ns1:props": [
                        {
                            "ns1:name": "Baz",
                            "ns1:code": "ABC"
                        },
                        {
                            "ns1:name": "Qux",
                            "ns1:code": "DEF"
                        }
                    ]
                }
            ]
        }
    }
}

But that leads to:

<RootElement>
  <ns1:id xmlns:ns1="http://my.namespace">1234</ns1:id>
  <ns1:name xmlns:ns1="http://my.namespace">Foo</ns1:name>
  <ns1:children xmlns:ns1="http://my.namespace">
    <ns1:id>5678</ns1:id>
    <ns1:name>Bar</ns1:name>
    <ns1:props>
      <ns1:name>Baz</ns1:name>
      <ns1:code>ABC</ns1:code>
    </ns1:props>
    <ns1:props>
      <ns1:name>Qux</ns1:name>
      <ns1:code>DEF</ns1:code>
    </ns1:props>
    [object Object]  <!-- ***** oops ***** -->
  </ns1:children>
</RootElement>

This is closer, but it includes a stringified arbitrary object in the result.

(also available on RunKit.)

So the basic question is simply how do I add a namespace to a JS array so that each element will include that namespace?

At the moment, I'm using the latter approach and post-processing the XML string to remove this extra [object Object] line, but that feels rather sleazy. Is there a better way?

Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103

0 Answers0