D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
home
/
etb1lp46s9ed
/
washeet.softurecs.com
/
node_modules
/
simple-xml-to-json
/
lib
/
Filename :
simpleXmlToJson.js
back
Copy
'use strict'; function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } const convertToJSON = ast => { return buildJSONFromNode(ast.value.children[0]) }; const buildJSONFromNode = node => { if (!node) return null const json = {}; switch (node.type) { case "ELEMENT": { let element = {}; const attribs = buildAttributes(node.value.attributes); const children = buildJSONFromNode(node.value.children); if (attribs) { element = Object.assign(element, attribs); } if (children) { const jsonChildren = buildChildren(node.value.children); element = Object.assign(element, jsonChildren); } json[node.value.type] = element; break } case "ATTRIBUTE": { const attribNameAndValue = node.value; json[attribNameAndValue.name] = attribNameAndValue.value; break } case "CONTENT": { return {content: node.value} } } return json }; const buildChildren = children => { if (!children || !Array.isArray(children) || children.length === 0) return null if (isContentChildren(children)) { return { content: children[0].value } } return { children: children.map(buildJSONFromNode) } }; const isContentChildren = children => children && Array.isArray(children) && children.length === 1 && children[0].type === "CONTENT"; const buildAttributes = arrayNodes => { if (arrayNodes && Array.isArray(arrayNodes)) { const jsonArray = arrayNodes.map(buildJSONFromNode); return jsonArray.reduce((agg, j) => Object.assign(agg, j), {}) } return null }; var astToJson = { convert: convertToJSON }; const Token$2 = (type, value) => ({ type, value }); var model = { Token: Token$2 }; const { Token: Token$1 } = model; const EOF_TOKEN = Token$1("EOF"); const isCharBlank = (char) => char === ' ' || char === '\n' || char === '\r' || char === '\t'; const skipXMLDocumentHeader = (xmlAsString, pos) => { if (xmlAsString.startsWith('<?xml', pos)) { const len = xmlAsString.length; while (pos < len) { if (xmlAsString[pos] !== '?') { pos++; } else if (xmlAsString[pos + 1] === '>') { return pos + 2 // skip "?>"" } else { pos++; } } } return pos }; const replaceQuotes = (str) => str.replace(/'/g, "'"); const getInitialPosForLexer = (xmlAsString) => { let pos = 0; while (pos < xmlAsString.length && isCharBlank(xmlAsString[pos])) pos++; return skipXMLDocumentHeader(xmlAsString, pos) }; function createLexer$1(xmlAsString) { let currentToken = null; let pos = getInitialPosForLexer(xmlAsString); let scopingElement = []; const peek = () => xmlAsString[pos]; const hasNext = () => currentToken !== EOF_TOKEN && pos < xmlAsString.length; const isBlankSpace = () => isCharBlank(xmlAsString[pos]); const skipQuotes = () => { if (hasNext() && isQuote(peek())) pos++; }; const isQuote = (char) => '"' === char || "'" === char; const skipSpaces = () => { while (hasNext() && isBlankSpace()) pos++; }; const readAlphaNumericCharsOrBrackets = (areSpecialCharsSupported) => { if (hasNext()) { if (xmlAsString[pos] === '<') { let buffer = '<'; pos++; if (hasNext() && xmlAsString[pos] === '/') { pos++; buffer = '</'; } else if ( hasNext() && xmlAsString[pos] === '!' && xmlAsString[pos + 1] === '-' && xmlAsString[pos + 2] === '-' ) { // its a comment pos++; pos++; pos++; buffer = '<!--'; } return buffer } else if (peek() === '/') { let buffer = '/'; pos++; if (hasNext() && peek() === '>') { pos++; buffer = '/>'; } return buffer } else if (xmlAsString[pos] === '=' || xmlAsString[pos] === '>') { const buffer = xmlAsString[pos]; pos++; return buffer } } return readAlphaNumericChars(!!areSpecialCharsSupported) }; const readAlphaNumericChars = (areSpecialCharsSupported) => { const ELEMENT_TYPE_MATCHER = /[a-zA-Z0-9_:-]/; const NAMES_VALS_CONTENT_MATCHER = /[^>=<]/u; const matcher = areSpecialCharsSupported ? NAMES_VALS_CONTENT_MATCHER : ELEMENT_TYPE_MATCHER; let start = pos; while (hasNext() && xmlAsString[pos].match(matcher)) pos++; return replaceQuotes(xmlAsString.substring(start, pos)) }; const isElementBegin = () => currentToken && currentToken.type === "OPEN_BRACKET"; const isAssignToAttribute = () => currentToken && currentToken.type === "ASSIGN"; const next = () => { const prevPos = pos; skipSpaces(); const numOfSpacesSkipped = pos - prevPos; if (!hasNext()) { currentToken = EOF_TOKEN; } else if (isElementBegin()) { // starting new element skipSpaces(); const buffer = readAlphaNumericCharsOrBrackets(false); currentToken = Token$1("ELEMENT_TYPE", buffer); scopingElement.push(buffer); } else if (isAssignToAttribute()) { // assign value to attribute skipQuotes(); const openingQuote = xmlAsString[pos - 1]; let start = pos; while (hasNext() && peek() !== openingQuote) pos++; const buffer = replaceQuotes(xmlAsString.substring(start, pos)); pos++; currentToken = Token$1("ATTRIB_VALUE", buffer); } else { skipSpaces(); let buffer = readAlphaNumericCharsOrBrackets(true); switch (buffer) { case '=': { if (currentToken.type === "ATTRIB_NAME") { currentToken = Token$1("ASSIGN"); } else { currentToken = Token$1("CONTENT", buffer); } break } case '</': { const start = pos; while (xmlAsString[pos] !== '>') pos++; currentToken = Token$1( "CLOSE_ELEMENT", xmlAsString.substring(start, pos) ); pos++; // skip the ">" scopingElement.pop(); break } case '/>': { const scopingElementName = scopingElement.pop(); currentToken = Token$1( "CLOSE_ELEMENT", scopingElementName ); break } case '<!--': { // skipComment contents const closingBuff = ['!', '-', '-']; while ( hasNext() && (closingBuff[2] !== '>' || closingBuff[1] !== '-' || closingBuff[0] !== '-') ) { closingBuff.shift(); closingBuff.push(xmlAsString[pos]); pos++; } return next() } case '>': { currentToken = Token$1("CLOSE_BRACKET"); break } case '<': { currentToken = Token$1("OPEN_BRACKET"); break } default: { // here we fall if we have alphanumeric string, which can be related to attributes, content or nothing if (buffer && buffer.length > 0) { if (currentToken.type === "CLOSE_BRACKET") { let suffix = ''; if (peek() !== '<') { suffix = readAlphaNumericChars(true); } currentToken = Token$1( "CONTENT", buffer + suffix ); } else if ( currentToken.type !== "ATTRIB_NAME" && currentToken.type !== "CONTENT" ) { if ( currentToken.type === "CLOSE_ELEMENT" ) { // we're assuming this is content, part of unstructured data buffer = ' '.repeat(numOfSpacesSkipped) + buffer; currentToken = Token$1("CONTENT", buffer); } else { // it should be an attribute name token currentToken = Token$1( "ATTRIB_NAME", buffer ); } } else { const contentBuffer = ' '.repeat(numOfSpacesSkipped) + buffer; // spaces included as content currentToken = Token$1( "CONTENT", contentBuffer ); } break } else { const errMsg = 'Unknown Syntax : "' + xmlAsString[pos] + '"'; throw new Error(errMsg) } } } } return currentToken }; return { peek, next, hasNext, // prettier-ignore ...({}) } } var lexer = { createLexer: createLexer$1 }; const { createLexer } = lexer; const { Token } = model; // AST Node types const [ROOT, ELEMENT, ATTRIBUTE, CONTENT] = [ 'ROOT', 'ELEMENT', 'ATTRIBUTE', 'CONTENT' ]; const Node = (type, value) => ({ type, value }); const ContentNode = (value) => Node(CONTENT, value); const ElementNode = (type, attributes, children) => { return Node(ELEMENT, { type, attributes, children }) }; const AttribNode = (name, value) => { return Node(ATTRIBUTE, { name, value }) }; const parseXML = (lexer) => { /* How does the grammar look? | expr: StructuredXML | UnstructuredXML | Content | StructuredXML: (openBracket + ElementName) + (AttributeList)* + closeBracket + (expr)* + closeElement | UnstructuredXML: Content* + expr* + Content* | Content: String | openBracket: < | closeBracket: > | closeElement: </ + ElementName + closeBracket | ElementName: String | AttributeList: AttributeName + "=" + AttributeValue + AttributeList* | AttributeName: String | AttributeValue: String */ const rootNode = Node(ROOT, { children: parseExpr(lexer, Token(ROOT, 'ROOT')) }); return rootNode }; const parseExpr = (lexer, scopingElement) => { const children = []; while (lexer.hasNext()) { const lexem = lexer.next(); switch (lexem.type) { case "OPEN_BRACKET": { const elementLexem = lexer.next(); const [elementAttributes, currentToken] = parseElementAttributes(lexer); let elementChildren = []; if (currentToken.type !== "CLOSE_ELEMENT") { elementChildren = parseExpr(lexer, elementLexem); } if ( elementChildren && elementChildren.length > 0 && elementChildren[0].type === "CONTENT" ) { elementChildren = reduceChildrenElements(elementChildren); } children.push( ElementNode( elementLexem.value, elementAttributes, elementChildren ) ); break } case "CLOSE_ELEMENT": { if (lexem.value === scopingElement.value) return children break } case "CONTENT": { children.push(ContentNode(lexem.value)); break } case "EOF": { return children } default: { throw new Error( `Unknown Lexem type: ${lexem.type} "${lexem.value}, scoping element: ${scopingElement.value}"` ) } } } return children }; const parseElementAttributes = (lexer) => { const attribs = []; let currentToken = lexer.peek(); if ( !lexer.hasNext() || (currentToken && currentToken.type === "CLOSE_BRACKET") || (currentToken && currentToken.type === "CLOSE_ELEMENT") ) { return [attribs, currentToken] } currentToken = lexer.next(); while ( lexer.hasNext() && currentToken && currentToken.type !== "CLOSE_BRACKET" && currentToken.type !== "CLOSE_ELEMENT" ) { const attribName = currentToken; lexer.next(); //assignment token const attribValue = lexer.next(); const attributeNode = AttribNode(attribName.value, attribValue.value); attribs.push(attributeNode); currentToken = lexer.next(); } return [attribs, currentToken] }; function reduceChildrenElements(elementChildren) { let reduced = [], buffer = ''; elementChildren.forEach((child) => { if (child.type === "CONTENT") { buffer += child.value; } else { if (buffer.length) { reduced.push(ContentNode(buffer)); buffer = ''; } reduced.push(child); } }); if (buffer.length) reduced.push(ContentNode(buffer)); return reduced } function transpile$1(xmlAsString, astConverter) { const lexer = createLexer(xmlAsString); const ast = parseXML(lexer); if (astConverter) { return astConverter.convert(ast) } return ast } var transpiler = { AttribNode, ContentNode, ElementNode, Node, transpile: transpile$1 }; const jsonConverter = astToJson; const { transpile } = transpiler; function convertXML(xmlAsString, customConverter) { return transpile(xmlAsString, customConverter || jsonConverter) } function createAST(xmlAsString) { return transpile(xmlAsString) } var xmlToJson = { convertXML, createAST }; var xmlToJson$1 = /*@__PURE__*/getDefaultExportFromCjs(xmlToJson); module.exports = xmlToJson$1;