New:Socket for Asana Is Now Available.Learn more
Get Started

fast-xml-parser

Package Overview
Dependencies
Maintainers
1
Versions
200
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fast-xml-parser - npm Package Compare versions

Comparing version
5.10.1
to
5.11.0
+6
-0
CHANGELOG.md

@@ -7,2 +7,8 @@ <small>Note: If you find missing information about particular minor version, that version must have been changed without any functional change in this library.</small>

**5.11.0 / 2026-08-16**
- feat: support for endIndex in node metadata (#850) [By [Pavel Dranichnikov](https://github.com/Wain-PC)]
- fix: don't crash on a closing tag with no matching opening tag (#861) [By [Haïm Dimer](https://github.com/hdimer)]
- fix: DOCTYPE to read SYSTEM/PUBLIC
- deps: strnum v2.4.2
**5.10.1 / 2026-07-17**

@@ -9,0 +15,0 @@ - fix: multiple DOCTYPE declarations.

+2
-2
{
"name": "fast-xml-parser",
"version": "5.10.1",
"version": "5.11.0",
"description": "Validate XML, Parse XML, Build XML without C/C++ based libraries",

@@ -90,5 +90,5 @@ "main": "./lib/fxp.cjs",

"path-expression-matcher": "^1.6.2",
"strnum": "^2.4.1",
"strnum": "^2.4.2",
"xml-naming": "^0.3.0"
}
}

@@ -22,3 +22,3 @@ # [fast-xml-parser](https://www.npmjs.com/package/fast-xml-parser)

- [@nodable/sax](https://github.com/nodable/sax) is a SAX parser based on [Flexible-XML-Parser](https://github.com/nodable/flexible-xml-parser). 3-4 times faster than `sax` and support all features of base package like incomplete input, streams, skipping certain tags from processing etc.
- [fast-xml-validator](https://github.com/NaturalIntelligence/fast-xml-validator) is a XML validator used in this package in past. Now, it supports more features, and faster. So recommend to use it directly.
- [fast-xml-validator](https://github.com/NaturalIntelligence/fast-xml-validator) is separated from this package. Has many features. Faster. You can exvlude particular tag from validation. And much more.
- [fast-xml-builder](https://github.com/NaturalIntelligence/fast-xml-builder) is a XML to JS Object builder used in this package in past. Now, it supports more features, and faster. So, recommend to use it directly.

@@ -25,0 +25,0 @@

@@ -752,2 +752,4 @@ /**

startIndex?: number;
/** The index, if available, of the character where the XML node ended in the input stream. */
endIndex?: number;
}

@@ -26,4 +26,19 @@ import { qName as isName } from 'xml-naming';

let hasBody = false, comment = false;
let quoteChar = null; // tracks an open SYSTEM/PUBLIC literal before the '[' body
let exp = "";
for (; i < xmlData.length; i++) {
// Inside a quoted external-identifier literal — XML allows '<'
// and '>' as plain data here, so they must not be interpreted
// as DOCTYPE structure until the matching quote closes.
if (quoteChar !== null) {
if (xmlData[i] === quoteChar) quoteChar = null;
exp += xmlData[i];
continue;
}
if (!hasBody && !comment && (xmlData[i] === '"' || xmlData[i] === "'")) {
quoteChar = xmlData[i];
exp += xmlData[i];
continue;
}
if (xmlData[i] === '<' && !comment) { //Determine the tag type

@@ -83,3 +98,3 @@ if (hasBody && hasSeq(xmlData, "!ENTITY", i)) {

}
if (angleBracketsCount !== 0) {
if (quoteChar !== null || angleBracketsCount !== 0) {
throw new Error(`Unclosed DOCTYPE`);

@@ -86,0 +101,0 @@ }

@@ -339,3 +339,8 @@ 'use strict';

currentNode = this.tagsNodeStack.pop();//avoid recursion, set the parent tag scope
//a closing tag with no matching opening tag leaves the stack empty
currentNode = this.tagsNodeStack.pop() || xmlObj;//avoid recursion, set the parent tag scope
if (options.captureMetaData && currentNode) {
currentNode.addEndIndex(closeIndex + 1);
}
textData = "";

@@ -366,2 +371,7 @@ i = closeIndex;

this.addChild(currentNode, childNode, this.readonlyMatcher, i);
if (options.captureMetaData) {
// closeIndex points at '?' of the closing '?>'
currentNode.addEndIndex(tagData.closeIndex + 2);
}
}

@@ -531,2 +541,6 @@

this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
if (options.captureMetaData) {
currentNode.addEndIndex(i + 1);
}
} else {

@@ -542,2 +556,6 @@ //selfClosing tag

this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
if (options.captureMetaData) {
currentNode.addEndIndex(closeIndex + 1);
}
this.matcher.pop(); // Pop self-closing tag

@@ -552,2 +570,6 @@ this.isCurrentNodeStopNode = false; // Reset flag

this.addChild(currentNode, childNode, this.readonlyMatcher, startIndex);
if (options.captureMetaData) {
currentNode.addEndIndex(result.closeIndex + 1);
}
this.matcher.pop(); // Pop unpaired tag

@@ -554,0 +576,0 @@ this.isCurrentNodeStopNode = false; // Reset flag

@@ -30,2 +30,6 @@ 'use strict';

// if requested, add the startIndex
this.addStartIndex(startIndex);
}
addStartIndex(startIndex) {
if (startIndex !== undefined) {

@@ -37,2 +41,12 @@ // Note: for now we just overwrite the metadata. If we had more complex metadata,

}
addEndIndex(endIndex) {
const lastChild = this.child[this.child.length - 1];
// endIndex is write-once: when updateTag drops a node, the last child is a
// previously completed sibling whose endIndex must not be overwritten
if (lastChild !== undefined && lastChild[METADATA_SYMBOL] !== undefined
&& lastChild[METADATA_SYMBOL].endIndex === undefined) {
lastChild[METADATA_SYMBOL].endIndex = endIndex;
}
}
/** symbol used for metadata */

@@ -39,0 +53,0 @@ static getMetaDataSymbol() {

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display