Comparing version 0.1.0 to 0.1.1
/* | ||
stacking xml parser | ||
The Just-Good-Enough XML Parser | ||
@@ -92,4 +92,6 @@ */ | ||
if ((c == '\t') || (c == '\r') || (c == '\n')) { //other unicode spaces are not treated as whitespace | ||
c = ' '; | ||
if (context.state != sContent) { | ||
if ((c == '\t') || (c == '\r') || (c == '\n')) { //other unicode spaces are not treated as whitespace | ||
c = ' '; | ||
} | ||
} | ||
@@ -99,5 +101,8 @@ | ||
context.token = context.token.trim(); // nonstandard space handling | ||
if ((context.state != sValue) && (context.state != sComment)) { // && (context.state != sContent) | ||
context.token = context.token.trim(); | ||
} | ||
context.keepToken = false; | ||
if (((context.state & 1) == 1) && (context.token != '')) { | ||
if (((context.state & 1) == 1) && ((context.token.trim() != '') || context.state == sValue)) { | ||
context.token = context.token.replaceAll('&','&'); | ||
@@ -118,3 +123,3 @@ context.token = context.token.replaceAll('"','"'); | ||
} | ||
if (context.state == sComment) { | ||
@@ -121,0 +126,0 @@ context.token = context.token.replaceAll('-- ',''); |
{ | ||
"name": "jgexml", | ||
"version": "0.1.0", | ||
"version": "0.1.1", | ||
"description": "The Just-Good-Enough XML Parser", | ||
@@ -5,0 +5,0 @@ "main": "jgeXml.js", |
@@ -13,3 +13,3 @@ 'use strict'; | ||
var context = {}; | ||
var prefixLen = 0; | ||
var depth = 0; | ||
@@ -20,9 +20,10 @@ while (!context.state || context.state != jgeXml.sEndDocument) { | ||
if (context.state == jgeXml.sElement) { | ||
prefixLen += 2; | ||
depth++; | ||
} | ||
else if (context.state == jgeXml.sEndElement) { | ||
prefixLen -= 2; | ||
depth--; | ||
} | ||
console.log(jgeXml.getStateName(context.state)+' '+context.position+' '+prefixLen+' '+context.token); | ||
console.log(jgeXml.getStateName(context.state)+' '+context.position+' '+depth+' '+context.token); | ||
} | ||
if (depth != 0) process.exitCode = 1; | ||
} |
@@ -12,12 +12,13 @@ 'use strict'; | ||
var prefixLen = 0; | ||
var depth = 0; | ||
jgeXml.parse(xml,function(state,token){ | ||
if (state == jgeXml.sElement) { | ||
prefixLen += 2; | ||
depth++; | ||
} | ||
else if (state == jgeXml.sEndElement) { | ||
prefixLen -= 2; | ||
depth--; | ||
} | ||
console.log(jgeXml.getStateName(state)+' '+prefixLen+' '+token); | ||
console.log(jgeXml.getStateName(state)+' '+depth+' '+token); | ||
if (depth != 0) process.exitCode = 1; | ||
}); |
155
xml2json.js
@@ -16,95 +16,141 @@ 'use strict'; | ||
function parseString(xml,attributePrefix) { | ||
function encode(token) { | ||
token = token.replaceAll('\\','\\\\'); | ||
token = token.replaceAll('\r','\\r'); | ||
token = token.replaceAll('\n','\\n'); | ||
token = token.replaceAll('\t','\\t'); | ||
token = token.replaceAll('"','\\"'); | ||
return token; | ||
} | ||
var s = '{'; | ||
var hasContent = false; | ||
var hasAttribute = false; | ||
var s; | ||
function getString() { | ||
return s; | ||
} | ||
function newContext() { | ||
var context = {}; | ||
context.position = s.length-1; //mutable | ||
context.anchor = context.position; //immutable | ||
context.hasContent = false; | ||
context.hasAttribute = false; | ||
return context; | ||
} | ||
function dump(stack) { | ||
for (var i=0;i<stack.length;i++) { | ||
console.log('Entry '+i+' points to '+stack[i].anchor+' ->'+s.charAt(stack[i].anchor)+'<'); | ||
} | ||
console.log('--'); | ||
} | ||
function parseString(xml,attributePrefix,valueProperty) { | ||
var stack = []; | ||
var depth = 0; //depth tracks the depth of XML element nesting, not the output JSON | ||
var lastElement = ''; | ||
var stack = []; | ||
var finished = 0; | ||
stack.push(1); | ||
s = '{'; | ||
stack.push(newContext()); | ||
jgeXml.parse(xml,function(state,token){ | ||
if (state == jgeXml.sContent) { | ||
if (token != '') { // maybe move this in to only omit hasContent = true ?? | ||
if (s.charAt(s.length-1) == '{') { | ||
s = s.substr(0,s.length-1); | ||
if (token != '') { | ||
var closeObject = false; | ||
// content should be following a property name not the beginning of an object | ||
// so remove assumption it was a container | ||
if ((!valueProperty) && (s.charAt(s.length-1) == '{')) { | ||
s = s.replaceAt(s.length-1,' '); | ||
} | ||
// if we're following another property, separate with a comma | ||
if (s.charAt(s.length-1) == '"') { | ||
s += ','; | ||
} | ||
if (hasAttribute) { | ||
s += ' "_" : '; | ||
// if we have had attributes, this is definitely a container not a primitive | ||
// treat this value as an anonymous property | ||
if ((stack[stack.length-1].hasAttribute) && (!valueProperty)) { | ||
s += ' "' + attributePrefix + '": '; | ||
} | ||
else { | ||
hasContent = true; | ||
if (stack[stack.length-1].hasContent) { | ||
//create array for mixed content/elements | ||
if (s.charAt(stack[stack.length-1].position) != '[') { | ||
s = s.insert(stack[stack.length-1].position,'['); | ||
} | ||
if (valueProperty) { | ||
s += ',{'; | ||
closeObject = true; | ||
} | ||
} | ||
stack[stack.length-1].hasContent = true; | ||
} | ||
s += '"' + token.replaceAll('"','\\"') + '"'; | ||
if (valueProperty) { | ||
s += '"value": '; | ||
} | ||
s += '"' + encode(token) + '"'; | ||
if (closeObject) { | ||
s += '}'; | ||
} | ||
} | ||
} | ||
else if (state == jgeXml.sEndElement) { | ||
// drop hanging comma | ||
if (s.charAt(s.length-1) == ',') { | ||
s = s.substr(0,s.length-1); | ||
} | ||
// if we're in an array, close it | ||
if (s.charAt(stack[stack.length-1]) == '[') { | ||
//dump(stack); | ||
if (s.charAt(stack[stack.length-1].position) == '[') { | ||
// if we're in an array, close it | ||
s += ']'; | ||
} | ||
//// if we're in an object, close it | ||
//if (s.charAt(stack[stack.length-2]) == '{') { | ||
// s += '}'; | ||
//} | ||
// close an empty element | ||
if (!hasContent) { | ||
if (s.charAt(stack[stack.length-1].anchor) == '{') { | ||
// if we're in an object, close it | ||
s += '}'; | ||
} | ||
hasContent = false; | ||
hasAttribute = false; | ||
lastElement = token; | ||
finished = stack.pop(); | ||
stack.pop(); | ||
depth--; | ||
lastElement = token+'<'+depth+'>'; | ||
} | ||
else if (state == jgeXml.sAttribute) { | ||
// if not the first attribute, separate the properties with a comma | ||
if (s.charAt(s.length-1) !== '{') { | ||
s += ','; | ||
} | ||
s += '"' + attributePrefix + token + '" : '; | ||
hasAttribute = true; | ||
s += '"' + attributePrefix + token + '": '; | ||
stack[stack.length-1].hasAttribute = true; | ||
} | ||
else if (state == jgeXml.sValue) { | ||
s += '"' + token.replaceAll('"','\\"') + '"'; | ||
s += '"' + encode(token) + '"'; | ||
} | ||
else if (state == jgeXml.sElement) { | ||
hasAttribute = false; | ||
if (s.charAt(s.length-1) !== '{') { | ||
// if this is not the first property, separate with a comma | ||
if (s.charAt(s.length-1) != '{') { | ||
s += ','; | ||
} | ||
if (token != lastElement) { | ||
if (s.charAt(stack[stack.length-1]) == '[') { | ||
if (token+'<'+depth+'>' != lastElement) { | ||
// element has changed, if we're in an array, terminate it just before the comma we (maybe) added | ||
if (s.charAt(stack[stack.length-1].position) == '[') { | ||
s = s.insert(s.length-1,']'); | ||
} | ||
s += '"' + token + '": '; | ||
stack[stack.length-1] = s.length; | ||
stack.push(s.length); | ||
s += '{'; | ||
stack[stack.length-1].position = s.length; //update position of previous element (array insertion point) | ||
} | ||
else { | ||
// array detected, new element matches previous endElement | ||
// array detected, new element matches previous endElement and at same depth | ||
// only need to insert array opening bracket once | ||
if (s.charAt(stack[stack.length-1]) != '[') { | ||
s = s.insert(stack[stack.length-1],'['); | ||
//s = s.replaceAt(stack[stack.length-1],'['); | ||
if (s.charAt(stack[stack.length-1].position) != '[') { | ||
s = s.insert(stack[stack.length-1].position,'['); | ||
} | ||
stack.push(s.length); | ||
//if (s.charAt(s.length-1) == '{') { | ||
// //anonymous object? | ||
// //s = s.substr(0,s.length-1); // drop previous opening brace | ||
// s += '"anon": '; | ||
//} | ||
s += '{'; | ||
} | ||
lastElement = token+'<'+depth+'>'; | ||
s += '{'; // here we assume all elements are containers not values, this supports attributes | ||
stack.push(newContext()); | ||
depth++; | ||
} | ||
}); | ||
// remove final trailing comma, if any | ||
if (s.charAt(s.length-1) == ',') { | ||
@@ -121,5 +167,6 @@ s = s.substr(0,s.length-1); | ||
module.exports = { | ||
xml2json : function(xml,attributePrefix) { | ||
return parseString(xml,attributePrefix); | ||
} | ||
xml2json : function(xml,attributePrefix,valueProperty) { | ||
return parseString(xml,attributePrefix,valueProperty); | ||
}, | ||
getString : getString | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
109236
30
538