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?
Description
We have some XML feeds (NITF) where the element name itself contains a dot, like
<body.content>. We usestopNodesto 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-matcherseems 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.contentgets rewritten to..body.contentin 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
Code
Output
expected data
Notes
A couple of things I ran into while looking at this, in case they help:
path-expression-matchercan already match the tag if you build the Expression with a different separator, for examplenew 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 internalinstanceof Expressioncheck in OrderedObjParser and gets ignored, andExpressionisn't re-exported fromfast-xml-parsereither.body\.content), which would letstopNodes: ['*.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?