@aws-sdk/xml-builder
Advanced tools
+236
-3
@@ -1,4 +0,1 @@ | ||
| const { parseXML } = require("./xml-parser"); | ||
| exports.parseXML = parseXML; | ||
| const ATTR_ESCAPE_RE = /[&<>"]/g; | ||
@@ -128,3 +125,239 @@ const ATTR_ESCAPE_MAP = { | ||
| function parseXML(xml) { | ||
| const state = new AwsXmlParser(xml); | ||
| return state.parse(); | ||
| } | ||
| class AwsXmlParser { | ||
| x; | ||
| i = 0; | ||
| z; | ||
| constructor(x) { | ||
| this.x = x; | ||
| this.x = x.replace(/\r\n?/g, "\n"); | ||
| this.z = this.x.length; | ||
| } | ||
| parse() { | ||
| const p = this; | ||
| const { z } = p; | ||
| while (p.i < z) { | ||
| p.trim(); | ||
| if (p.i >= z) { | ||
| break; | ||
| } | ||
| if (p.isNext("<?")) { | ||
| p.readTo("?>"); | ||
| p.trim(); | ||
| } | ||
| else if (p.isNext("<!--")) { | ||
| p.readTo("-->"); | ||
| p.trim(); | ||
| } | ||
| else if (p.isNext("<!DOCTYPE", false)) { | ||
| p.skipDoctype(); | ||
| p.trim(); | ||
| } | ||
| else if (p.x[p.i] === "<") { | ||
| const root = p.parseTag(); | ||
| return { [root.tag]: root.value }; | ||
| } | ||
| else { | ||
| throw new Error("@aws-sdk XML parse error: unexpected content."); | ||
| } | ||
| } | ||
| throw new Error("@aws-sdk XML parse error: no root element."); | ||
| } | ||
| isNext(s, caseSensitive = true) { | ||
| const p = this; | ||
| if (caseSensitive) { | ||
| return p.x.startsWith(s, p.i); | ||
| } | ||
| return p.x.toLowerCase().startsWith(s.toLowerCase(), p.i); | ||
| } | ||
| readTo(stop) { | ||
| const p = this; | ||
| const _i = p.x.indexOf(stop, p.i); | ||
| if (_i === -1) { | ||
| throw new Error(`@aws-sdk XML parse error: expected "${stop}" not found.`); | ||
| } | ||
| const result = p.x.slice(p.i, _i); | ||
| p.i = _i + stop.length; | ||
| return result; | ||
| } | ||
| trim() { | ||
| const p = this; | ||
| while (p.i < p.z && " \t\r\n".includes(p.x[p.i])) { | ||
| ++p.i; | ||
| } | ||
| } | ||
| readAttrValue() { | ||
| const p = this; | ||
| const quote = p.x[p.i]; | ||
| ++p.i; | ||
| let value = ""; | ||
| while (p.i < p.z && p.x[p.i] !== quote) { | ||
| value += p.x[p.i++]; | ||
| } | ||
| ++p.i; | ||
| return p.decodeEntities(value); | ||
| } | ||
| parseTag() { | ||
| const p = this; | ||
| ++p.i; | ||
| let tag = ""; | ||
| while (p.i < p.z && !" \t\r\n>/".includes(p.x[p.i])) { | ||
| tag += p.x[p.i++]; | ||
| } | ||
| let hasAttrs = false; | ||
| const attrs = Object.create(null); | ||
| while (p.i < p.z) { | ||
| p.trim(); | ||
| if (">/".includes(p.x[p.i])) { | ||
| break; | ||
| } | ||
| let name = ""; | ||
| while (p.i < p.z && !"= \t\r\n>/?".includes(p.x[p.i])) { | ||
| name += p.x[p.i++]; | ||
| } | ||
| p.trim(); | ||
| if (p.x[p.i] !== "=") { | ||
| break; | ||
| } | ||
| ++p.i; | ||
| p.trim(); | ||
| attrs[name] = p.readAttrValue(); | ||
| hasAttrs = true; | ||
| } | ||
| if (p.i >= p.z) { | ||
| throw new Error("@aws-sdk XML parse error: unexpected end of input."); | ||
| } | ||
| if (p.x[p.i] === "/") { | ||
| ++p.i; | ||
| if (p.i >= p.z || p.x[p.i] !== ">") { | ||
| throw new Error("@aws-sdk XML parse error: expected > at the end of self-closing tag."); | ||
| } | ||
| ++p.i; | ||
| Object.setPrototypeOf(attrs, Object.prototype); | ||
| return { tag, value: hasAttrs ? attrs : "" }; | ||
| } | ||
| if (p.x[p.i] !== ">") { | ||
| throw new Error("@aws-sdk XML parse error: expected > at the end of opening tag."); | ||
| } | ||
| ++p.i; | ||
| const textParts = []; | ||
| const childTags = []; | ||
| let hasElementChild = false; | ||
| while (p.i < p.z) { | ||
| if (p.isNext("</")) { | ||
| break; | ||
| } | ||
| if (p.x[p.i] === "<") { | ||
| if (p.isNext("<!--")) { | ||
| p.readTo("-->"); | ||
| } | ||
| else if (p.isNext("<![CDATA[")) { | ||
| p.i += 9; | ||
| textParts.push(p.readTo("]]>")); | ||
| } | ||
| else if (p.isNext("<?")) { | ||
| p.readTo("?>"); | ||
| } | ||
| else { | ||
| hasElementChild = true; | ||
| childTags.push(p.parseTag()); | ||
| } | ||
| } | ||
| else { | ||
| let text = ""; | ||
| while (p.i < p.z && p.x[p.i] !== "<") { | ||
| text += p.x[p.i++]; | ||
| } | ||
| textParts.push(p.decodeEntities(text)); | ||
| } | ||
| } | ||
| if (!p.isNext("</")) { | ||
| throw new Error(`@aws-sdk XML parse error: missing closing tag </${tag}>.`); | ||
| } | ||
| p.i += 2; | ||
| const closeTag = p.readTo(">").trim(); | ||
| if (closeTag !== tag) { | ||
| throw new Error(`@aws-sdk XML parse error: mismatched tags <${tag}> and </${closeTag}>.`); | ||
| } | ||
| if (!hasAttrs && textParts.length === 0 && !hasElementChild) { | ||
| return { tag, value: "" }; | ||
| } | ||
| if (!hasAttrs && !hasElementChild) { | ||
| const text = textParts.length === 1 ? textParts[0] : textParts.join(""); | ||
| if (text.trim() === "" && text.includes("\n")) { | ||
| return { tag, value: "" }; | ||
| } | ||
| return { tag, value: text }; | ||
| } | ||
| const obj = Object.create(null); | ||
| for (const text of textParts) { | ||
| if (text.trim() === "" && text.includes("\n")) { | ||
| continue; | ||
| } | ||
| obj["#text"] = "#text" in obj ? obj["#text"] + text : text; | ||
| } | ||
| for (const child of childTags) { | ||
| if (child.tag in obj) { | ||
| if (Array.isArray(obj[child.tag])) { | ||
| obj[child.tag].push(child.value); | ||
| } | ||
| else { | ||
| obj[child.tag] = [obj[child.tag], child.value]; | ||
| } | ||
| } | ||
| else { | ||
| obj[child.tag] = child.value; | ||
| } | ||
| } | ||
| for (const [k, v] of Object.entries(attrs)) { | ||
| obj[k] = v; | ||
| } | ||
| Object.setPrototypeOf(obj, Object.prototype); | ||
| return { tag, value: obj }; | ||
| } | ||
| static ENTITIES = { | ||
| amp: "&", | ||
| lt: "<", | ||
| gt: ">", | ||
| quot: '"', | ||
| apos: "'", | ||
| }; | ||
| skipDoctype() { | ||
| const p = this; | ||
| p.i += 9; | ||
| let depth = 0; | ||
| while (p.i < p.z) { | ||
| const c = p.x[p.i]; | ||
| if (c === "[") { | ||
| ++depth; | ||
| } | ||
| else if (c === "]") { | ||
| --depth; | ||
| } | ||
| else if (c === ">" && depth === 0) { | ||
| ++p.i; | ||
| return; | ||
| } | ||
| ++p.i; | ||
| } | ||
| throw new Error("@aws-sdk XML parse error: unclosed DOCTYPE."); | ||
| } | ||
| decodeEntities(s) { | ||
| return s.replace(/&(?:#x([0-9a-fA-F]{1,6})|#(\d{1,7})|([a-zA-Z][a-zA-Z0-9]{0,30}));/g, (_, hex, dec, named) => { | ||
| if (hex) { | ||
| return String.fromCharCode(parseInt(hex, 16)); | ||
| } | ||
| if (dec) { | ||
| return String.fromCharCode(parseInt(dec, 10)); | ||
| } | ||
| return AwsXmlParser.ENTITIES[named] ?? ""; | ||
| }); | ||
| } | ||
| } | ||
| exports.XmlNode = XmlNode; | ||
| exports.XmlText = XmlText; | ||
| exports.parseXML = parseXML; |
+3
-4
| { | ||
| "name": "@aws-sdk/xml-builder", | ||
| "version": "3.972.31", | ||
| "version": "3.972.32", | ||
| "description": "XML utilities for the AWS SDK", | ||
| "dependencies": { | ||
| "@smithy/types": "^4.14.3", | ||
| "@smithy/types": "^4.15.0", | ||
| "tslib": "^2.6.2" | ||
@@ -48,4 +48,3 @@ }, | ||
| "react-native": { | ||
| "./dist-es/xml-parser": "./dist-es/xml-parser.browser", | ||
| "./dist-cjs/xml-parser": "./dist-cjs/xml-parser.browser" | ||
| "./dist-es/xml-parser": "./dist-es/xml-parser.browser" | ||
| }, | ||
@@ -52,0 +51,0 @@ "homepage": "https://github.com/aws/aws-sdk-js-v3/tree/main/packages-internal/xml-builder", |
| let parser; | ||
| exports.parseXML = function parseXML(xmlString) { | ||
| if (!parser) { | ||
| parser = new DOMParser(); | ||
| } | ||
| const xmlDocument = parser.parseFromString(xmlString, "application/xml"); | ||
| if (xmlDocument.getElementsByTagName("parsererror").length > 0) { | ||
| throw new Error("DOMParser XML parsing error."); | ||
| } | ||
| const xmlToObj = (node) => { | ||
| if (node.nodeType === Node.TEXT_NODE) { | ||
| if (node.textContent?.trim()) { | ||
| return node.textContent; | ||
| } | ||
| } | ||
| if (node.nodeType === Node.ELEMENT_NODE) { | ||
| const element = node; | ||
| if (element.attributes.length === 0 && element.childNodes.length === 0) { | ||
| return ""; | ||
| } | ||
| const obj = {}; | ||
| const attributes = Array.from(element.attributes); | ||
| for (const attr of attributes) { | ||
| obj[`${attr.name}`] = attr.value; | ||
| } | ||
| const childNodes = Array.from(element.childNodes); | ||
| for (const child of childNodes) { | ||
| const childResult = xmlToObj(child); | ||
| if (childResult != null) { | ||
| const childName = child.nodeName; | ||
| if (childNodes.length === 1 && attributes.length === 0 && childName === "#text") { | ||
| return childResult; | ||
| } | ||
| if (childName in obj) { | ||
| if (Array.isArray(obj[childName])) { | ||
| obj[childName].push(childResult); | ||
| } | ||
| else { | ||
| obj[childName] = [obj[childName], childResult]; | ||
| } | ||
| } | ||
| else { | ||
| obj[childName] = childResult; | ||
| } | ||
| } | ||
| else if (childNodes.length === 1 && attributes.length === 0) { | ||
| return element.textContent; | ||
| } | ||
| } | ||
| return obj; | ||
| } | ||
| return null; | ||
| }; | ||
| return { | ||
| [xmlDocument.documentElement.nodeName]: xmlToObj(xmlDocument.documentElement), | ||
| }; | ||
| }; |
| exports.parseXML = function parseXML(xml) { | ||
| const state = new AwsXmlParser(xml); | ||
| return state.parse(); | ||
| }; | ||
| class AwsXmlParser { | ||
| x; | ||
| i = 0; | ||
| z; | ||
| constructor(x) { | ||
| this.x = x; | ||
| this.x = x.replace(/\r\n?/g, "\n"); | ||
| this.z = this.x.length; | ||
| } | ||
| parse() { | ||
| const p = this; | ||
| const { z } = p; | ||
| while (p.i < z) { | ||
| p.trim(); | ||
| if (p.i >= z) { | ||
| break; | ||
| } | ||
| if (p.isNext("<?")) { | ||
| p.readTo("?>"); | ||
| p.trim(); | ||
| } | ||
| else if (p.isNext("<!--")) { | ||
| p.readTo("-->"); | ||
| p.trim(); | ||
| } | ||
| else if (p.isNext("<!DOCTYPE", false)) { | ||
| p.skipDoctype(); | ||
| p.trim(); | ||
| } | ||
| else if (p.x[p.i] === "<") { | ||
| const root = p.parseTag(); | ||
| return { [root.tag]: root.value }; | ||
| } | ||
| else { | ||
| throw new Error("@aws-sdk XML parse error: unexpected content."); | ||
| } | ||
| } | ||
| throw new Error("@aws-sdk XML parse error: no root element."); | ||
| } | ||
| isNext(s, caseSensitive = true) { | ||
| const p = this; | ||
| if (caseSensitive) { | ||
| return p.x.startsWith(s, p.i); | ||
| } | ||
| return p.x.toLowerCase().startsWith(s.toLowerCase(), p.i); | ||
| } | ||
| readTo(stop) { | ||
| const p = this; | ||
| const _i = p.x.indexOf(stop, p.i); | ||
| if (_i === -1) { | ||
| throw new Error(`@aws-sdk XML parse error: expected "${stop}" not found.`); | ||
| } | ||
| const result = p.x.slice(p.i, _i); | ||
| p.i = _i + stop.length; | ||
| return result; | ||
| } | ||
| trim() { | ||
| const p = this; | ||
| while (p.i < p.z && " \t\r\n".includes(p.x[p.i])) { | ||
| ++p.i; | ||
| } | ||
| } | ||
| readAttrValue() { | ||
| const p = this; | ||
| const quote = p.x[p.i]; | ||
| ++p.i; | ||
| let value = ""; | ||
| while (p.i < p.z && p.x[p.i] !== quote) { | ||
| value += p.x[p.i++]; | ||
| } | ||
| ++p.i; | ||
| return p.decodeEntities(value); | ||
| } | ||
| parseTag() { | ||
| const p = this; | ||
| ++p.i; | ||
| let tag = ""; | ||
| while (p.i < p.z && !" \t\r\n>/".includes(p.x[p.i])) { | ||
| tag += p.x[p.i++]; | ||
| } | ||
| let hasAttrs = false; | ||
| const attrs = Object.create(null); | ||
| while (p.i < p.z) { | ||
| p.trim(); | ||
| if (">/".includes(p.x[p.i])) { | ||
| break; | ||
| } | ||
| let name = ""; | ||
| while (p.i < p.z && !"= \t\r\n>/?".includes(p.x[p.i])) { | ||
| name += p.x[p.i++]; | ||
| } | ||
| p.trim(); | ||
| if (p.x[p.i] !== "=") { | ||
| break; | ||
| } | ||
| ++p.i; | ||
| p.trim(); | ||
| attrs[name] = p.readAttrValue(); | ||
| hasAttrs = true; | ||
| } | ||
| if (p.i >= p.z) { | ||
| throw new Error("@aws-sdk XML parse error: unexpected end of input."); | ||
| } | ||
| if (p.x[p.i] === "/") { | ||
| ++p.i; | ||
| if (p.i >= p.z || p.x[p.i] !== ">") { | ||
| throw new Error("@aws-sdk XML parse error: expected > at the end of self-closing tag."); | ||
| } | ||
| ++p.i; | ||
| Object.setPrototypeOf(attrs, Object.prototype); | ||
| return { tag, value: hasAttrs ? attrs : "" }; | ||
| } | ||
| if (p.x[p.i] !== ">") { | ||
| throw new Error("@aws-sdk XML parse error: expected > at the end of opening tag."); | ||
| } | ||
| ++p.i; | ||
| const textParts = []; | ||
| const childTags = []; | ||
| let hasElementChild = false; | ||
| while (p.i < p.z) { | ||
| if (p.isNext("</")) { | ||
| break; | ||
| } | ||
| if (p.x[p.i] === "<") { | ||
| if (p.isNext("<!--")) { | ||
| p.readTo("-->"); | ||
| } | ||
| else if (p.isNext("<![CDATA[")) { | ||
| p.i += 9; | ||
| textParts.push(p.readTo("]]>")); | ||
| } | ||
| else if (p.isNext("<?")) { | ||
| p.readTo("?>"); | ||
| } | ||
| else { | ||
| hasElementChild = true; | ||
| childTags.push(p.parseTag()); | ||
| } | ||
| } | ||
| else { | ||
| let text = ""; | ||
| while (p.i < p.z && p.x[p.i] !== "<") { | ||
| text += p.x[p.i++]; | ||
| } | ||
| textParts.push(p.decodeEntities(text)); | ||
| } | ||
| } | ||
| if (!p.isNext("</")) { | ||
| throw new Error(`@aws-sdk XML parse error: missing closing tag </${tag}>.`); | ||
| } | ||
| p.i += 2; | ||
| const closeTag = p.readTo(">").trim(); | ||
| if (closeTag !== tag) { | ||
| throw new Error(`@aws-sdk XML parse error: mismatched tags <${tag}> and </${closeTag}>.`); | ||
| } | ||
| if (!hasAttrs && textParts.length === 0 && !hasElementChild) { | ||
| return { tag, value: "" }; | ||
| } | ||
| if (!hasAttrs && !hasElementChild) { | ||
| const text = textParts.length === 1 ? textParts[0] : textParts.join(""); | ||
| if (text.trim() === "" && text.includes("\n")) { | ||
| return { tag, value: "" }; | ||
| } | ||
| return { tag, value: text }; | ||
| } | ||
| const obj = Object.create(null); | ||
| for (const text of textParts) { | ||
| if (text.trim() === "" && text.includes("\n")) { | ||
| continue; | ||
| } | ||
| obj["#text"] = "#text" in obj ? obj["#text"] + text : text; | ||
| } | ||
| for (const child of childTags) { | ||
| if (child.tag in obj) { | ||
| if (Array.isArray(obj[child.tag])) { | ||
| obj[child.tag].push(child.value); | ||
| } | ||
| else { | ||
| obj[child.tag] = [obj[child.tag], child.value]; | ||
| } | ||
| } | ||
| else { | ||
| obj[child.tag] = child.value; | ||
| } | ||
| } | ||
| for (const [k, v] of Object.entries(attrs)) { | ||
| obj[k] = v; | ||
| } | ||
| Object.setPrototypeOf(obj, Object.prototype); | ||
| return { tag, value: obj }; | ||
| } | ||
| static ENTITIES = { | ||
| amp: "&", | ||
| lt: "<", | ||
| gt: ">", | ||
| quot: '"', | ||
| apos: "'", | ||
| }; | ||
| skipDoctype() { | ||
| const p = this; | ||
| p.i += 9; | ||
| let depth = 0; | ||
| while (p.i < p.z) { | ||
| const c = p.x[p.i]; | ||
| if (c === "[") { | ||
| ++depth; | ||
| } | ||
| else if (c === "]") { | ||
| --depth; | ||
| } | ||
| else if (c === ">" && depth === 0) { | ||
| ++p.i; | ||
| return; | ||
| } | ||
| ++p.i; | ||
| } | ||
| throw new Error("@aws-sdk XML parse error: unclosed DOCTYPE."); | ||
| } | ||
| decodeEntities(s) { | ||
| return s.replace(/&(?:#x([0-9a-fA-F]{1,6})|#(\d{1,7})|([a-zA-Z][a-zA-Z0-9]{0,30}));/g, (_, hex, dec, named) => { | ||
| if (hex) { | ||
| return String.fromCharCode(parseInt(hex, 16)); | ||
| } | ||
| if (dec) { | ||
| return String.fromCharCode(parseInt(dec, 10)); | ||
| } | ||
| return AwsXmlParser.ENTITIES[named] ?? ""; | ||
| }); | ||
| } | ||
| } |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
0
-100%41266
-5.26%28
-6.67%924
-5.91%Updated