NaturalIntelligence / fast-xml-parser

Validate XML, Parse XML and Build XML rapidly without C/C++ based libraries and no callback.
https://naturalintelligence.github.io/fast-xml-parser/
MIT License
2.5k stars 302 forks source link

Self closing tags fail with stopNodes. #470

Closed OmarOmeiri closed 2 years ago

OmarOmeiri commented 2 years ago

Description

The XMLParser fails when stopNode is an empty (self-closing) tag. If I remove the problematic tag, everything works fine.

Input

<?xml version="1.0"?>
<ArrayOfControleAcionarioAcionista xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ControleAcionarioAcionista>
    <ControlesAcionariosAcionistasFilhos>
      <ControleAcionarioAcionista>
        <ControlesAcionariosPreferenciais>
          <ControleAcionarioPreferencial>
            <CodigoClasseAcaoPreferencial>0</CodigoClasseAcaoPreferencial>
            <QuantidadeAcao>0</QuantidadeAcao>
            <PercentualAcao>0.000000</PercentualAcao>
          </ControleAcionarioPreferencial>
        </ControlesAcionariosPreferenciais>
        <ControlesAcionariosAcionistasFilhos>
          <ControleAcionarioAcionista>
            <ControlesAcionariosPreferenciais />
            <ControlesAcionariosAcionistasFilhos>
              <ControleAcionarioAcionista>
                <ControlesAcionariosPreferenciais />
                <ControlesAcionariosAcionistasFilhos /><!-- This is the problematic tag -->
                <Nivel>0</Nivel>
              </ControleAcionarioAcionista>
            </ControlesAcionariosAcionistasFilhos>
            <Nivel>0</Nivel>
          </ControleAcionarioAcionista>
        </ControlesAcionariosAcionistasFilhos>
        <Nivel>0</Nivel>
      </ControleAcionarioAcionista>
    </ControlesAcionariosAcionistasFilhos>
    <Nivel>0</Nivel>
  </ControleAcionarioAcionista>
</ArrayOfControleAcionarioAcionista>

Code

import { X2jOptionsOptional, XMLParser } from 'fast-xml-parser';
import { readFile, writeFile } from 'fs/promises';

const PATH = `${__dirname}/ControleAcionario.xml`;

const ignoreTags = [
  /ControlesAcionariosAcionistasFilhos/i,
];

/**
 * I have also tried with:
 * ArrayOfControleAcionarioAcionista.ControleAcionarioAcionista.ControlesAcionariosAcionistasFilhos
 */
const stopNodes = [
  '*.ControlesAcionariosAcionistasFilhos',
];

const tagValueProcessor = (tagName: string, tagValue: string, jPath: string) => {
  if (ignoreTags.some((re) => re.test(jPath))) return '';
  return tagValue;
};

const options: X2jOptionsOptional = {
  tagValueProcessor,
  trimValues: true,
  stopNodes,
};

(async () => {
  const parser = new XMLParser(options);
  const xml = (await readFile(PATH)).toString();
  const json = JSON.stringify(parser.parse(xml), null, 2);
  await writeFile(`${__dirname}/test.json`, json);
})();

Output

.../node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js:299
            if(!result) throw new Error(`Unexpected end of ${tagName}`);
                              ^
Error: Unexpected end of ControlesAcionariosAcionistasFilhos
    at OrderedObjParser.parseXml (.../node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js:299:31)
    at XMLParser.parse (.../node_modules/fast-xml-parser/src/xmlparser/XMLParser.js:35:48)
    at .../playground/xmlparse/xmlparse.ts:32:38

expected data

{
  "?xml": "",
  "ArrayOfControleAcionarioAcionista": {
    "ControleAcionarioAcionista": {
      "ControlesAcionariosAcionistasFilhos": "",
      "Nivel": 0
    }
  }
}

Would you like to work on this issue?

Bookmark this repository for further updates.

github-actions[bot] commented 2 years ago

I'm glad you find this repository helpful. I'll try to address your issue ASAP. You can watch the repo for new changes or star it.