From 8938336e1c001593e949612b8d95dcb2556e1e2c Mon Sep 17 00:00:00 2001
From: Alex Litskevich <alitskevich@gmail.com>
Date: Sun, 19 Mar 2017 20:26:13 +0300
Subject: [PATCH] XLSX Defined Names

closes #162 h/t @alitskevich
---
 bits/72_wbxml.js | 20 +++++++++++++++++---
 xlsx.flow.js     | 20 +++++++++++++++++---
 xlsx.js          | 20 +++++++++++++++++---
 3 files changed, 51 insertions(+), 9 deletions(-)

diff --git a/bits/72_wbxml.js b/bits/72_wbxml.js
index 9048628..2c1e134 100644
--- a/bits/72_wbxml.js
+++ b/bits/72_wbxml.js
@@ -2,9 +2,11 @@
 var wbnsregex = /<\w+:workbook/;
 function parse_wb_xml(data, opts)/*:WorkbookFile*/ {
 	if(!data) throw new Error("Could not find file");
-	var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, xmlns: "" };
+	var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, Names:{'!names':[]}, xmlns: "" };
 	var pass = false, xmlns = "xmlns";
-	(data.match(tagregex)||[]).forEach(function xml_wb(x) {
+	var dname = {}, dnstart = 0;
+	/*(data.match(tagregex)||[]).forEach */
+	data.replace(tagregex, function xml_wb(x, idx) {
 		var y = parsexmltag(x);
 		switch(strip_ns(y[0])) {
 			case '<?xml': break;
@@ -59,7 +61,18 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ {
 			case '<definedNames>': case '<definedNames': pass=true; break;
 			case '</definedNames>': pass=false; break;
 			/* 18.2.5    definedName CT_DefinedName + */
-			case '<definedName': case '<definedName/>': case '</definedName>': break;
+			case '<definedName': {
+				dname = {};
+				dname.Name = y.name;
+				if(y.comment) dname.Comment = y.comment;
+				dnstart = idx + x.length;
+			}	break;
+			case '</definedName>': {
+				dname.Ref = data.slice(dnstart, idx);
+				wb.Names[dname.Name] = dname;
+				wb.Names['!names'].push(dname.Name);
+			} break;
+			case '<definedName/>': break;
 
 			/* 18.2.2  calcPr CT_CalcPr ? */
 			case '<calcPr': delete y[0]; wb.CalcPr = y; break;
@@ -111,6 +124,7 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ {
 
 			default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in workbook');
 		}
+		return x;
 	});
 	if(XMLNS.main.indexOf(wb.xmlns) === -1) throw new Error("Unknown Namespace: " + wb.xmlns);
 
diff --git a/xlsx.flow.js b/xlsx.flow.js
index ff917de..1a05868 100644
--- a/xlsx.flow.js
+++ b/xlsx.flow.js
@@ -9513,9 +9513,11 @@ function check_wb(wb) {
 var wbnsregex = /<\w+:workbook/;
 function parse_wb_xml(data, opts)/*:WorkbookFile*/ {
 	if(!data) throw new Error("Could not find file");
-	var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, xmlns: "" };
+	var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, Names:{'!names':[]}, xmlns: "" };
 	var pass = false, xmlns = "xmlns";
-	(data.match(tagregex)||[]).forEach(function xml_wb(x) {
+	var dname = {}, dnstart = 0;
+	/*(data.match(tagregex)||[]).forEach */
+	data.replace(tagregex, function xml_wb(x, idx) {
 		var y = parsexmltag(x);
 		switch(strip_ns(y[0])) {
 			case '<?xml': break;
@@ -9570,7 +9572,18 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ {
 			case '<definedNames>': case '<definedNames': pass=true; break;
 			case '</definedNames>': pass=false; break;
 			/* 18.2.5    definedName CT_DefinedName + */
-			case '<definedName': case '<definedName/>': case '</definedName>': break;
+			case '<definedName': {
+				dname = {};
+				dname.Name = y.name;
+				if(y.comment) dname.Comment = y.comment;
+				dnstart = idx + x.length;
+			}	break;
+			case '</definedName>': {
+				dname.Ref = data.slice(dnstart, idx);
+				wb.Names[dname.Name] = dname;
+				wb.Names['!names'].push(dname.Name);
+			} break;
+			case '<definedName/>': break;
 
 			/* 18.2.2  calcPr CT_CalcPr ? */
 			case '<calcPr': delete y[0]; wb.CalcPr = y; break;
@@ -9622,6 +9635,7 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ {
 
 			default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in workbook');
 		}
+		return x;
 	});
 	if(XMLNS.main.indexOf(wb.xmlns) === -1) throw new Error("Unknown Namespace: " + wb.xmlns);
 
diff --git a/xlsx.js b/xlsx.js
index ea29657..7c0ac53 100644
--- a/xlsx.js
+++ b/xlsx.js
@@ -9460,9 +9460,11 @@ function check_wb(wb) {
 var wbnsregex = /<\w+:workbook/;
 function parse_wb_xml(data, opts) {
 	if(!data) throw new Error("Could not find file");
-	var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, xmlns: "" };
+	var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, Names:{'!names':[]}, xmlns: "" };
 	var pass = false, xmlns = "xmlns";
-	(data.match(tagregex)||[]).forEach(function xml_wb(x) {
+	var dname = {}, dnstart = 0;
+	/*(data.match(tagregex)||[]).forEach */
+	data.replace(tagregex, function xml_wb(x, idx) {
 		var y = parsexmltag(x);
 		switch(strip_ns(y[0])) {
 			case '<?xml': break;
@@ -9517,7 +9519,18 @@ function parse_wb_xml(data, opts) {
 			case '<definedNames>': case '<definedNames': pass=true; break;
 			case '</definedNames>': pass=false; break;
 			/* 18.2.5    definedName CT_DefinedName + */
-			case '<definedName': case '<definedName/>': case '</definedName>': break;
+			case '<definedName': {
+				dname = {};
+				dname.Name = y.name;
+				if(y.comment) dname.Comment = y.comment;
+				dnstart = idx + x.length;
+			}	break;
+			case '</definedName>': {
+				dname.Ref = data.slice(dnstart, idx);
+				wb.Names[dname.Name] = dname;
+				wb.Names['!names'].push(dname.Name);
+			} break;
+			case '<definedName/>': break;
 
 			/* 18.2.2  calcPr CT_CalcPr ? */
 			case '<calcPr': delete y[0]; wb.CalcPr = y; break;
@@ -9569,6 +9582,7 @@ function parse_wb_xml(data, opts) {
 
 			default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in workbook');
 		}
+		return x;
 	});
 	if(XMLNS.main.indexOf(wb.xmlns) === -1) throw new Error("Unknown Namespace: " + wb.xmlns);