@@ -121,10 +121,11 @@ export default class OrderedObjParser {
121121 this . isCurrentNodeStopNode = false ;
122122
123123 // Pre-compile stopNodes expressions
124- if ( this . options . stopNodes && this . options . stopNodes . length > 0 ) {
124+ const stopNodesOpts = this . options . stopNodes ;
125+ if ( stopNodesOpts && stopNodesOpts . length > 0 ) {
125126 this . stopNodeExpressions = [ ] ;
126- for ( let i = 0 ; i < this . options . stopNodes . length ; i ++ ) {
127- const stopNodeExp = this . options . stopNodes [ i ] ;
127+ for ( let i = 0 ; i < stopNodesOpts . length ; i ++ ) {
128+ const stopNodeExp = stopNodesOpts [ i ] ;
128129 if ( typeof stopNodeExp === 'string' ) {
129130 // Convert string to Expression object
130131 this . stopNodeExpressions . push ( new Expression ( stopNodeExp ) ) ;
@@ -303,9 +304,13 @@ const parseXml = function (xmlData) {
303304 // Reset entity expansion counters for this document
304305 this . entityExpansionCount = 0 ;
305306 this . currentExpandedLength = 0 ;
307+ this . docTypeEntitiesKeys = [ ] ;
308+ this . lastEntitiesKeys = Object . keys ( this . lastEntities ) ;
309+ this . htmlEntitiesKeys = Object . keys ( this . htmlEntities ) ;
306310
307311 const docTypeReader = new DocTypeReader ( this . options . processEntities ) ;
308- for ( let i = 0 ; i < xmlData . length ; i ++ ) { //for each char in XML data
312+ const xmlLen = xmlData . length ;
313+ for ( let i = 0 ; i < xmlLen ; i ++ ) { //for each char in XML data
309314 const ch = xmlData [ i ] ;
310315 if ( ch === '<' ) {
311316 // const nextIndex = i+1;
@@ -382,6 +387,7 @@ const parseXml = function (xmlData) {
382387 && xmlData . charCodeAt ( i + 2 ) === 68 ) { //'!D'
383388 const result = docTypeReader . readDocType ( xmlData , i ) ;
384389 this . docTypeEntities = result . entities ;
390+ this . docTypeEntitiesKeys = Object . keys ( this . docTypeEntities ) || [ ]
385391 i = result . i ;
386392 } else if ( c1 === 33
387393 && xmlData . charCodeAt ( i + 2 ) === 91 ) { // '!['
@@ -407,7 +413,7 @@ const parseXml = function (xmlData) {
407413 // Safety check: readTagExp can return undefined
408414 if ( ! result ) {
409415 // Log context for debugging
410- const context = xmlData . substring ( Math . max ( 0 , i - 50 ) , Math . min ( xmlData . length , i + 50 ) ) ;
416+ const context = xmlData . substring ( Math . max ( 0 , i - 50 ) , Math . min ( xmlLen , i + 50 ) ) ;
411417 throw new Error ( `readTagExp returned undefined at position ${ i } . Context: "${ context } "` ) ;
412418 }
413419
@@ -623,7 +629,7 @@ function replaceEntitiesValue(val, tagName, jPath) {
623629 }
624630
625631 // Replace DOCTYPE entities
626- for ( const entityName of Object . keys ( this . docTypeEntities ) ) {
632+ for ( const entityName of this . docTypeEntitiesKeys ) {
627633 const entity = this . docTypeEntities [ entityName ] ;
628634 const matches = val . match ( entity . regx ) ;
629635
@@ -657,7 +663,7 @@ function replaceEntitiesValue(val, tagName, jPath) {
657663 }
658664 if ( val . indexOf ( '&' ) === - 1 ) return val ;
659665 // Replace standard entities
660- for ( const entityName of Object . keys ( this . lastEntities ) ) {
666+ for ( const entityName of this . lastEntitiesKeys ) {
661667 const entity = this . lastEntities [ entityName ] ;
662668 const matches = val . match ( entity . regex ) ;
663669 if ( matches ) {
@@ -675,7 +681,7 @@ function replaceEntitiesValue(val, tagName, jPath) {
675681
676682 // Replace HTML entities if enabled
677683 if ( this . options . htmlEntities ) {
678- for ( const entityName of Object . keys ( this . htmlEntities ) ) {
684+ for ( const entityName of this . htmlEntitiesKeys ) {
679685 const entity = this . htmlEntities [ entityName ] ;
680686 const matches = val . match ( entity . regex ) ;
681687 if ( matches ) {
@@ -717,7 +723,6 @@ function saveTextToParentTag(textData, parentNode, matcher, isLeafNode) {
717723 return textData ;
718724}
719725
720- //TODO: use jPath to simplify the logic
721726/**
722727 * @param {Array<Expression> } stopNodeExpressions - Array of compiled Expression objects
723728 * @param {Matcher } matcher - Current path matcher
@@ -826,7 +831,8 @@ function readStopNodeData(xmlData, tagName, i) {
826831 // Starting at 1 since we already have an open tag
827832 let openTagCount = 1 ;
828833
829- for ( ; i < xmlData . length ; i ++ ) {
834+ const xmllen = xmlData . length ;
835+ for ( ; i < xmllen ; i ++ ) {
830836 if ( xmlData [ i ] === "<" ) {
831837 const c1 = xmlData . charCodeAt ( i + 1 ) ;
832838 if ( c1 === 47 ) { //close tag '/'
0 commit comments