[gnumeric] [xlsx] Basic external ref support



commit 13420953c3093609f862fb88baf84becf55181f5
Author: Jody Goldberg <jody gnome org>
Date:   Tue Apr 28 17:27:35 2009 -0400

    [xlsx] Basic external ref support
    
    Still requires
    1) storing the values
    2) names
    3) re-organize parser to handle sheetnames with spaces.
    4) proper life cycle support for the extern workbook.
    5) Use (4) for xls
---
 NEWS                       |    3 ++
 plugins/excel/ChangeLog    |    7 ++++
 plugins/excel/xlsx-read.c  |   66 +++++++++++++++++++++++++++++++++++++++++++-
 plugins/excel/xlsx-utils.c |   42 ++++++++++++++++++++++++----
 plugins/excel/xlsx-utils.h |    6 ++-
 src/parse-util.c           |   27 +++++++++++------
 src/parse-util.h           |    6 ++--
 src/parser.y               |    8 ++++-
 8 files changed, 141 insertions(+), 24 deletions(-)

diff --git a/NEWS b/NEWS
index d0a9e15..0c15c8b 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,9 @@ Andreas:
 	* Fix some divergence between character weight in the label properties
 	  dialog and the label itself.
 
+Jody:
+	* XLSX start reading external refs.
+
 Morten:
 	* Fix xls save problem with sheets that are too big for the format.
 	* Fix global-name .gnumeric warning.  [#580227]
diff --git a/plugins/excel/ChangeLog b/plugins/excel/ChangeLog
index 533827f..f62e571 100644
--- a/plugins/excel/ChangeLog
+++ b/plugins/excel/ChangeLog
@@ -1,3 +1,10 @@
+2009-04-28  Jody Goldberg <jody gnome org>
+
+	* xlsx-read.c : initial work on reading external refs.   Still broken
+	  for refs to sheets with spaces in their names '[1]A Space!A1' thanks
+	  to massively silly quoting conventions.  This will take a parser
+	  re-org to handle.
+
 2009-04-26  Morten Welinder  <terra gnome org>
 
 	* ms-excel-write.c (excel_sheet_extent): Fix off-by-one when we
diff --git a/plugins/excel/xlsx-read.c b/plugins/excel/xlsx-read.c
index 7dc8514..175257f 100644
--- a/plugins/excel/xlsx-read.c
+++ b/plugins/excel/xlsx-read.c
@@ -198,6 +198,10 @@ typedef struct {
 		GHashTable *by_obj;
 		XLSXAxisInfo *info;
 	} axis;
+
+	/* external refs */
+       	Workbook *external_ref;
+	Sheet 	 *external_ref_sheet;
 } XLSXReadState;
 typedef struct {
 	GnmString	*str;
@@ -3986,6 +3990,66 @@ xlsx_sheet_begin (GsfXMLIn *xin, xmlChar const **attrs)
 			(GDestroyNotify) g_free);
 }
 
+/**************************************************************************************************/
+
+static void
+xlsx_read_external_book (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	XLSXReadState *state = (XLSXReadState *)xin->user_state;
+	GsfOpenPkgRel const *rel = gsf_open_pkg_lookup_rel_by_type (
+		gsf_xml_in_get_input (xin), 
+		"http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath";);
+	if (NULL != rel && gsf_open_pkg_rel_is_extern (rel))
+		state->external_ref = xlsx_conventions_add_extern_ref (
+			state->convs, gsf_open_pkg_rel_get_target (rel));
+}
+static void
+xlsx_read_external_book_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
+{
+	XLSXReadState *state = (XLSXReadState *)xin->user_state;
+	state->external_ref = NULL;
+}
+static void
+xlsx_read_external_sheetname (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	XLSXReadState *state = (XLSXReadState *)xin->user_state;
+	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+		if (0 == strcmp (attrs[0], "val"))
+			workbook_sheet_attach (state->external_ref,
+				state->external_ref_sheet = sheet_new (state->external_ref, attrs[1], 256, 65536));
+}
+static void
+xlsx_read_external_sheetname_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
+{
+	XLSXReadState *state = (XLSXReadState *)xin->user_state;
+	state->external_ref_sheet = NULL;
+}
+
+static GsfXMLInNode const xlsx_extern_dtd[] = {
+GSF_XML_IN_NODE_FULL (START, START, -1, NULL, GSF_XML_NO_CONTENT, FALSE, TRUE, NULL, NULL, 0),
+GSF_XML_IN_NODE_FULL (START, LINK, XL_NS_SS, "externalLink", GSF_XML_NO_CONTENT, TRUE, TRUE, xlsx_read_external_book, xlsx_read_external_book_end, 0),
+  GSF_XML_IN_NODE (LINK, BOOK, XL_NS_SS, "externalBook", GSF_XML_NO_CONTENT, NULL, NULL),
+  GSF_XML_IN_NODE (BOOK, SHEET_NAMES, XL_NS_SS, "sheetNames", GSF_XML_NO_CONTENT, NULL, NULL),
+    GSF_XML_IN_NODE (SHEET_NAMES, SHEET_NAME, XL_NS_SS, "sheetName", GSF_XML_NO_CONTENT, xlsx_read_external_sheetname, xlsx_read_external_sheetname_end),
+  GSF_XML_IN_NODE (BOOK, SHEET_DATASET, XL_NS_SS, "sheetDataSet", GSF_XML_NO_CONTENT, NULL, NULL),
+    GSF_XML_IN_NODE (SHEET_DATASET, SHEET_DATA, XL_NS_SS, "sheetData", GSF_XML_NO_CONTENT, NULL, NULL),
+      GSF_XML_IN_NODE (SHEET_DATA, ROW, XL_NS_SS, "row", GSF_XML_NO_CONTENT, NULL, NULL),
+        GSF_XML_IN_NODE (ROW, CELL, XL_NS_SS, "cell", GSF_XML_NO_CONTENT, NULL, NULL),
+          GSF_XML_IN_NODE (CELL, VAL, XL_NS_SS, "v", GSF_XML_NO_CONTENT, NULL, NULL),
+
+GSF_XML_IN_NODE_END
+};
+
+static void
+xlsx_wb_external_ref (GsfXMLIn *xin, xmlChar const **attrs)
+{
+	for (; attrs != NULL && attrs[0] && attrs[1] ; attrs += 2)
+		if (gsf_xml_in_namecmp (xin, attrs[0], XL_NS_DOC_REL, "id"))
+			xlsx_parse_rel_by_id (xin, attrs[1], xlsx_extern_dtd, xlsx_ns);
+}
+
+/**************************************************************************************************/
+
 static void
 xlsx_wb_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
 {
@@ -4039,7 +4103,7 @@ GSF_XML_IN_NODE_FULL (START, WORKBOOK, XL_NS_SS, "workbook", GSF_XML_NO_CONTENT,
     GSF_XML_IN_NODE (FGROUPS, FGROUP,	 XL_NS_SS, "functionGroup", GSF_XML_NO_CONTENT, NULL, NULL),
   GSF_XML_IN_NODE (WORKBOOK, WEB_PUB,	 XL_NS_SS, "webPublishing", GSF_XML_NO_CONTENT, NULL, NULL),
   GSF_XML_IN_NODE (WORKBOOK, EXTERNS,	 XL_NS_SS, "externalReferences", GSF_XML_NO_CONTENT, NULL, NULL),
-    GSF_XML_IN_NODE (EXTERNS, EXTERN,	 XL_NS_SS, "externalReference", GSF_XML_NO_CONTENT, NULL, NULL),
+    GSF_XML_IN_NODE (EXTERNS, EXTERN,	 XL_NS_SS, "externalReference", GSF_XML_NO_CONTENT, xlsx_wb_external_ref, NULL),
   GSF_XML_IN_NODE (WORKBOOK, NAMES,	 XL_NS_SS, "definedNames", GSF_XML_NO_CONTENT, NULL, NULL),
     GSF_XML_IN_NODE (NAMES, NAME,	 XL_NS_SS, "definedName", GSF_XML_NO_CONTENT, NULL, NULL),
   GSF_XML_IN_NODE (WORKBOOK, PIVOTCACHES,      XL_NS_SS, "pivotCaches", GSF_XML_NO_CONTENT, NULL, NULL),
diff --git a/plugins/excel/xlsx-utils.c b/plugins/excel/xlsx-utils.c
index 3ce0397..a8894eb 100644
--- a/plugins/excel/xlsx-utils.c
+++ b/plugins/excel/xlsx-utils.c
@@ -28,13 +28,16 @@
 
 #include "parse-util.h"
 #include "position.h"
+#include "workbook.h"
 #include "sheet.h"
 #include "func.h"
+#include <goffice/app/go-doc.h>
 #include <glib-object.h>
 
 typedef struct {
 	GnmConventions base;
-	GHashTable *extern_ids;
+	GHashTable *extern_id_by_wb;
+	GHashTable *extern_wb_by_id;
 } XLSXExprConventions;
 
 static void
@@ -42,17 +45,27 @@ xlsx_add_extern_id (GnmConventionsOut *out, Workbook *wb)
 {
 	if (wb != out->pp->wb) {
 		XLSXExprConventions const *xconv = (XLSXExprConventions const *)out->convs;
-		char *id = g_hash_table_lookup (xconv->extern_ids, wb);
+		char *id = g_hash_table_lookup (xconv->extern_id_by_wb, wb);
 		if (NULL == id) {
 			id = g_strdup_printf ("[%u]",
-				g_hash_table_size (xconv->extern_ids));
+				g_hash_table_size (xconv->extern_id_by_wb));
 			g_object_ref (wb);
-			g_hash_table_insert (xconv->extern_ids, wb, id);
+			g_hash_table_insert (xconv->extern_id_by_wb, wb, id);
 		}
 		g_string_append (out->accum, id);
 	}
 }
 
+static Workbook *
+xlsx_lookup_external_wb (GnmConventions const *convs,
+			 G_GNUC_UNUSED Workbook *ref_wb,
+			 char const *name)
+{
+	XLSXExprConventions const *xconv = (XLSXExprConventions const *)convs;
+	g_print ("lookup '%s'\n", name);
+	return g_hash_table_lookup (xconv->extern_wb_by_id, name);
+}
+
 static void
 xlsx_cellref_as_string (GnmConventionsOut *out,
 			GnmCellRef const *cell_ref,
@@ -90,6 +103,19 @@ xlsx_rangeref_as_string (GnmConventionsOut *out, GnmRangeRef const *ref)
 		rangeref_as_string (out, ref);
 }
 
+Workbook *
+xlsx_conventions_add_extern_ref (GnmConventions *convs, char const *path)
+{
+	XLSXExprConventions *xconv = (XLSXExprConventions *)convs;
+	Workbook *res = g_object_new (WORKBOOK_TYPE, NULL);
+	(void) go_doc_set_uri (GO_DOC (res), path);
+	g_hash_table_insert (xconv->extern_wb_by_id,
+		g_strdup_printf ("%d", g_hash_table_size (xconv->extern_wb_by_id) + 1),
+		res);
+	g_print ("add %d = '%s'\n", g_hash_table_size (xconv->extern_wb_by_id), path);
+	return res;
+}
+
 GnmConventions *
 xlsx_conventions_new (void)
 {
@@ -99,6 +125,7 @@ xlsx_conventions_new (void)
 
 	convs->decimal_sep_dot		= TRUE;
 	convs->input.range_ref		= rangeref_parse;
+	convs->input.external_wb	= xlsx_lookup_external_wb;
 	convs->output.cell_ref		= xlsx_cellref_as_string;
 	convs->output.range_ref		= xlsx_rangeref_as_string;
 	convs->range_sep_colon		= TRUE;
@@ -107,8 +134,10 @@ xlsx_conventions_new (void)
 	convs->array_col_sep		= ',';
 	convs->array_row_sep		= ';';
 	convs->output.translated		= FALSE;
-	xconv->extern_ids = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+	xconv->extern_id_by_wb = g_hash_table_new_full (g_direct_hash, g_direct_equal,
 		(GDestroyNotify) g_object_unref, g_free);
+	xconv->extern_wb_by_id = g_hash_table_new_full (g_str_hash, g_str_equal,
+		g_free, (GDestroyNotify) g_object_unref);
 
 	return convs;
 }
@@ -117,6 +146,7 @@ void
 xlsx_conventions_free (GnmConventions *convs)
 {
 	XLSXExprConventions *xconv = (XLSXExprConventions *)convs;
-	g_hash_table_destroy (xconv->extern_ids);
+	g_hash_table_destroy (xconv->extern_id_by_wb);
+	g_hash_table_destroy (xconv->extern_wb_by_id);
 	gnm_conventions_free (convs);
 }
diff --git a/plugins/excel/xlsx-utils.h b/plugins/excel/xlsx-utils.h
index 226cf52..13c6387 100644
--- a/plugins/excel/xlsx-utils.h
+++ b/plugins/excel/xlsx-utils.h
@@ -35,7 +35,9 @@ enum {
 	XL_NS_PKG_REL
 };
 
-GnmConventions *xlsx_conventions_new  (void);
-void		xlsx_conventions_free (GnmConventions *conv);
+GnmConventions	*xlsx_conventions_new  (void);
+void		 xlsx_conventions_free (GnmConventions *conv);
+Workbook	*xlsx_conventions_add_extern_ref (GnmConventions *conv,
+						  char const *path);
 
 #endif /* GNM_XLSX_UTILS_H */
diff --git a/src/parse-util.c b/src/parse-util.c
index 867e6b4..6507f89 100644
--- a/src/parse-util.c
+++ b/src/parse-util.c
@@ -808,6 +808,7 @@ unquote (char *dst, char const *src, int n)
 
 /**
  * wbref_parse :
+ * @convs : #GnmConventions const
  * @start :
  * @wb :
  *
@@ -815,9 +816,10 @@ unquote (char *dst, char const *src, int n)
  *           If the string is a valid workbook known name it returns a pointer
  *           the end of the name.
  *           Otherwise returns @start and does not modify @wb.
- * **/
+ **/
 static char const *
-wbref_parse (char const *start, Workbook **wb, Workbook *ref_wb)
+wbref_parse (GnmConventions const *convs,
+	     char const *start, Workbook **wb, Workbook *ref_wb)
 {
 	/* Is this an external reference ? */
 	if (*start == '[') {
@@ -843,9 +845,11 @@ wbref_parse (char const *start, Workbook **wb, Workbook *ref_wb)
 		} else
 			unquote (name, start+2, end-start-2);
 
-		tmp_wb = gnm_app_workbook_get_by_name
-			(name,
-			 ref_wb ? go_doc_get_uri ((GODoc *)ref_wb) : NULL);
+		if (convs->input.external_wb)
+			tmp_wb = (*convs->input.external_wb) (convs, ref_wb, name);
+		else
+			tmp_wb = gnm_app_workbook_get_by_name (name,
+				 ref_wb ? go_doc_get_uri ((GODoc *)ref_wb) : NULL);
 		if (tmp_wb == NULL)
 			return NULL;
 		*wb = tmp_wb;
@@ -857,6 +861,7 @@ wbref_parse (char const *start, Workbook **wb, Workbook *ref_wb)
 
 /**
  * sheetref_parse :
+ * @convs :
  * @start :
  * @sheet :
  * @wb    :
@@ -867,8 +872,9 @@ wbref_parse (char const *start, Workbook **wb, Workbook *ref_wb)
  *           the end of the name.
  *           Otherwise returns @start and does not modify @sheet.
  **/
-char const *
-sheetref_parse (char const *start, Sheet **sheet, Workbook const *wb,
+static char const *
+sheetref_parse (GnmConventions const *convs,
+		char const *start, Sheet **sheet, Workbook const *wb,
 		gboolean allow_3d)
 {
 	GString *sheet_name;
@@ -1031,15 +1037,15 @@ rangeref_parse (GnmRangeRef *res, char const *start, GnmParsePos const *pp,
 	wb = pp->wb;
 	ref_wb = wb ? wb : pp->sheet->workbook;
 	start_wb = start;
-	start_sheet = wbref_parse (start, &wb, ref_wb);
+	start_sheet = wbref_parse (convs, start, &wb, ref_wb);
 	if (start_sheet == NULL)
 		return start; /* TODO error unknown workbook */
-	ptr = sheetref_parse (start_sheet, &res->a.sheet, wb, TRUE);
+	ptr = sheetref_parse (convs, start_sheet, &res->a.sheet, wb, TRUE);
 	if (ptr == NULL)
 		return start; /* TODO error unknown sheet */
 	if (ptr != start_sheet) {
 		if (*ptr == ':') { /* 3d ref */
-			ptr = sheetref_parse (ptr+1, &res->b.sheet, wb, FALSE);
+			ptr = sheetref_parse (convs, ptr+1, &res->b.sheet, wb, FALSE);
 			if (ptr == NULL)
 				return start; /* TODO error unknown sheet */
 		} else
@@ -1318,6 +1324,7 @@ gnm_conventions_new_full (unsigned size)
 	convs->input.range_ref		= rangeref_parse;
 	convs->input.name		= std_name_parser;
 	convs->input.func		= std_func_map;
+	convs->input.external_wb	= NULL;
 
 	convs->output.decimal_digits	= GNM_DIG;
 	convs->output.translated	= TRUE;
diff --git a/src/parse-util.h b/src/parse-util.h
index f9bad48..1c07c95 100644
--- a/src/parse-util.h
+++ b/src/parse-util.h
@@ -33,9 +33,6 @@ char const *rangeref_parse	(GnmRangeRef *res, char const *in,
 				 GnmConventions const *convs);
 				 /* GError **err); */
 
-char const *sheetref_parse	(char const *start, Sheet **sheet,
-				 Workbook const *wb, gboolean allow_3d);
-
 char const *cell_coord_name	(int col, int row);
 char const *cell_name		(GnmCell const *cell);
 
@@ -156,6 +153,9 @@ struct _GnmConventions {
 					Workbook *scope,
 					char const *name,
 					GnmExprList *args);
+		Workbook *(*external_wb) (GnmConventions const *convs,
+					 Workbook *ref_wb,
+					 char const *unquoted_name);
 	} input;
 
 /* Export specific functions ----------------------------------- */
diff --git a/src/parser.y b/src/parser.y
index 518790b..e1fdc1c 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -726,6 +726,7 @@ string_opt_quote : STRING
 		 | QUOTED_STRING
 		 ;
 
+/* only used for names */
 workbookref : '[' string_opt_quote ']'  {
 		char const *wb_name = value_peek_string ($2->constant.value);
 		Workbook *ref_wb = state->pos
@@ -735,8 +736,11 @@ workbookref : '[' string_opt_quote ']'  {
 			      ? state->pos->sheet->workbook
 			      : NULL))
 			: NULL;
-		Workbook *wb = gnm_app_workbook_get_by_name
-			(wb_name,
+		Workbook *wb;
+		if (state->convs->input.external_wb)
+			wb = (*state->convs->input.external_wb) (state->convs, ref_wb, wb_name);
+		else
+			wb = gnm_app_workbook_get_by_name (wb_name,
 			 ref_wb ? go_doc_get_uri ((GODoc *)ref_wb) : NULL);
 
 		if (wb != NULL) {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]