UNPKG

rn-xml-handler

Version:

A simple XML Decoder and Encoder for React Native (and Expo)

175 lines (142 loc) 4.41 kB
import { XMLTag } from "./xmlTag"; export class XMLParser { private static _parseFromString(xmlText: string) { xmlText = XMLParser._encodeCDATAValues(xmlText); let cleanXmlText = xmlText .replace(/\s{2,}/g, " ") .replace(/\\t\\n\\r/g, "") .replace(/>/g, ">\n") .replace(/\]\]/g, "]]\n"); let rawXmlData: XMLTag[] = []; cleanXmlText.split("\n").map((element) => { element = element.trim(); if (!element || element.indexOf("?xml") > -1) { return; } if (element.indexOf("<") == 0 && element.indexOf("CDATA") < 0) { let parsedTag = XMLParser._parseTag(element); if (parsedTag) { rawXmlData.push(parsedTag); if (element.match(/\/\s*>$/)) { let closingTag = XMLParser._parseTag("</" + parsedTag.name + ">"); if (closingTag) { rawXmlData.push(closingTag); } } } } else { rawXmlData[rawXmlData.length - 1].value += ` ${XMLParser._parseValue( element )}`; } }); return XMLParser._convertTagsArrayToTree(rawXmlData)[0]; } private static _encodeCDATAValues(xmlText: string) { let cdataRegex = new RegExp(/<!\[CDATA\[([^\]\]]+)\]\]/gi); let result = cdataRegex.exec(xmlText); while (result) { if (result.length > 1) { xmlText = xmlText.replace(result[1], encodeURIComponent(result[1])); } result = cdataRegex.exec(xmlText); } return xmlText; } private static _parseTag(tagText: string): XMLTag | undefined { let cleanTagText = tagText.match( /([^\s]*)=('([^']*?)'|"([^"]*?)")|([\/?\w\-\:]+)/g ); if (cleanTagText !== null && cleanTagText !== undefined) { let tag: XMLTag = new XMLTag({ name: cleanTagText.shift()?.replace(/\/\s*$/, "") ?? "", }); cleanTagText.map((attribute) => { let attributeKeyVal = attribute.split("="); if (attributeKeyVal.length < 2) { return; } let attributeKey = attributeKeyVal[0]; let attributeVal = ""; if (attributeKeyVal.length === 2) { attributeVal = attributeKeyVal[1]; } else { attributeKeyVal = attributeKeyVal.slice(1); attributeVal = attributeKeyVal.join("="); } tag.attributes[attributeKey] = attributeVal .replace(/^"/g, "") .replace(/^'/g, "") .replace(/"$/g, "") .replace(/'$/g, "") .trim(); }); return tag; } return undefined; } private static _parseValue(tagValue: string) { if (tagValue.indexOf("CDATA") < 0) { return tagValue.trim(); } return tagValue.substring( tagValue.lastIndexOf("[") + 1, tagValue.indexOf("]") ); } private static _convertTagsArrayToTree(xml: XMLTag[]) { let xmlTree = []; while (xml.length > 0) { let tag = xml.shift(); if ( (tag?.value && tag.value.indexOf("</") > -1) || tag?.name.match(/\/$/) ) { tag.name = tag.name.replace(/\/$/, "").trim(); tag.value = tag.value.substring(0, tag.value.indexOf("</")).trim(); xmlTree.push(tag); continue; } if (tag?.name.indexOf("/") == 0) { break; } if (tag) { xmlTree.push(tag); tag.children = XMLParser._convertTagsArrayToTree(xml); tag.value = decodeURIComponent(tag.value.trim()); } } return xmlTree; } private static _toString(xml: XMLTag) { var xmlText = XMLParser._convertTagToText(xml); if (xml.children.length > 0) { xml.children.map((child) => { xmlText += XMLParser._toString(child); }); xmlText += "</" + xml.name + ">"; } return xmlText; } private static _convertTagToText(tag: XMLTag) { var tagText = "<" + tag.name; for (var attribute in tag.attributes) { tagText += " " + attribute + '="' + tag.attributes[attribute] + '"'; } if (tag.value.length > 0) { tagText += ">" + tag.value; } else { tagText += ">"; } if (tag.children.length === 0) { tagText += "</" + tag.name + ">"; } return tagText; } static parseFromString(xmlText: string) { return XMLParser._parseFromString(xmlText); } static toString(xml: XMLTag) { return XMLParser._toString(xml); } }