Skip to content

stopNodes no longer matches tag names containing a literal dot on CommonJS #838

Description

@diegoarff
  • Are you running the latest version? (reproduced on 5.8.0)
  • Have you included sample input, output, error, and expected output?
  • Have you checked if you are using correct configuration?
  • Did you try online tool?
  • Have you checked the docs for helpful APIs and examples?

Description

We have some XML feeds (NITF) where the element name itself contains a dot, like <body.content>. We use stopNodes to keep that element's inner HTML as raw text instead of parsing it into objects. This worked fine on 5.4.0, but after upgrading it stopped working, and the contents come back as a parsed object instead of a string.

Digging into it, the switch to path-expression-matcher seems to be the cause. Every . in a stopNodes path is now treated as a hierarchy separator, so there is no way to say "the tag is literally named body.content". *.body.content gets rewritten to ..body.content in OptionsBuilder, and the matcher then reads that as a <content> nested inside a <body> rather than the single <body.content> element. I couldn't find any way to escape the dot in the pattern.

Input

<root><body><body.content><p>Hello</p><b>world</b></body.content></body></root>

Code

const { XMLParser } = require('fast-xml-parser');

const xml = `<root><body><body.content><p>Hello</p><b>world</b></body.content></body></root>`;
const out = new XMLParser({ stopNodes: ['*.body.content'] }).parse(xml);

console.log(typeof out.root.body['body.content'], JSON.stringify(out.root.body['body.content']));

Output

// 5.8.0, and every release since the path-expression-matcher change
object {"p":"Hello","b":"world"}

expected data

// what 5.4.0 returns: the stop node is kept as raw text
string "<p>Hello</p><b>world</b>"

Notes

A couple of things I ran into while looking at this, in case they help:

  • path-expression-matcher can already match the tag if you build the Expression with a different separator, for example new Expression('//body.content', { separator: '/' }) returns true for the path. But that escape hatch isn't reachable from here: the published CommonJS build bundles its own copy of the matcher, so an Expression I construct from the package fails the internal instanceof Expression check in OrderedObjParser and gets ignored, and Expression isn't re-exported from fast-xml-parser either.
  • The cleanest fix looks like adding a way to escape the separator in the matcher (for example body\.content), which would let stopNodes: ['*.body\\.content'] work again.

Happy to open a PR if it sounds reasonable. Let me know if there is a preferred approach to handle this.

Would you like to work on this issue?

  • Yes
  • No

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions