1

I have an XML file which looks like this:

<Item prop="foo">
  <A key="1">
  <B key="2">
  <A key="3">
  <C key="4">
  <A key="5">
  <A key="6">
</Item>
<Item .../>
<Item .../>

I want to parse this file into an array of Items, looking like the following:

[
  {
    "prop": "foo",
    "list": [
      { "key": "1" },
      { "key": "2" },
      { "key": "3" },
      { "key": "4" },
      { "key": "5" },
      { "key": "6" }
    ]
  },
  { ...item }
  { ...item }
]

I.e. to process all the A, B and C tags in order and into the same array.

I am using xml2json, which uses node-expat to parse the file. Is this at all possible using node-expat or any existing npm package? The reason I ask is because I don't want to be writing my own parser in a compiled language if at all possible.

Thanks

Fela Maslen
  • 2,022
  • 3
  • 25
  • 46

1 Answers1

3

Are the number of node A, B, C small and known?

If so, you can try camaro like below

EDIT: xml has to be valid, in the example above, it's not properly closed.

const transform = require('camaro')
const xml = `
<Item prop="foo">
  <A key="1"/>
  <B key="2"/>
  <A key="3"/>
  <C key="4"/>
  <A key="5"/>
  <A key="6"/>
</Item>
`

const { output } = transform(xml, {
    output: [
        '//Item',
        {
            prop: '@prop',
            list: ['A|B|C', { key: '@key' , tag: 'name()'}]
        }
    ]
})

console.log(JSON.stringify(output, null, 2))

Output

[
  {
    "list": [
      {
        "key": "1",
        "tag": "A"
      },
      {
        "key": "2",
        "tag": "B"
      },
      {
        "key": "3",
        "tag": "A"
      },
      {
        "key": "4",
        "tag": "C"
      },
      {
        "key": "5",
        "tag": "A"
      },
      {
        "key": "6",
        "tag": "A"
      }
    ],
    "prop": "foo"
  }
]
Tuan Anh Tran
  • 6,807
  • 6
  • 37
  • 54
  • This look great, but I'm getting the following warning: `(node:3186) Warning: N-API is an experimental feature and could change at any time.`. Is this production ready? – Fela Maslen Apr 06 '18 at 17:27
  • Another question: would it be possible to add, as a property of the object, the tag which was matched by `A|B|C`? I.e. to have something like `{"key":"4","tag":"C"}` for each item. – Fela Maslen Apr 06 '18 at 17:32
  • 1
    @felamaslen please use version 2.x.x. Ver 3 is using latest N-API which is still experimental feature. – Tuan Anh Tran Apr 07 '18 at 00:03
  • 1
    I misunderstood your question. it should be updated to be like this `list: ['A|B|C', { key: '@key' , tag: 'name()'}]` – Tuan Anh Tran Apr 07 '18 at 12:14