[glom] Tests: Validate all examples against the DTD, and correct the DTD.



commit d6520fbcc469ec11252339d71bb718a436a44258
Author: Murray Cumming <murrayc murrayc com>
Date:   Thu Dec 10 17:41:51 2009 +0100

    Tests: Validate all examples against the DTD, and correct the DTD.
    
    * tests/dtd/test_example_sqlite: Renamed to test_file_validation.sh.
    * glom/Makefile_tests.am: Adapted.
    * glom/libglom/document/document.cc: save_before(): Correct the saving
    of group privileges so they are really inside the group nodes. Avoid
    saving unnamed groups, as seen in the example files.
    * glom/glom_document.dtd: Several corrections to fix the validation of
    the example files, though I don't like that DTDs don't seem to give
    us any way to say that the sequence of child elements is irrelevant.
    I don't like enforcing the sequence.

 ChangeLog                             |   14 +++++
 Makefile_tests.am                     |    4 +-
 examples/example_film_manager.glom    |   33 ++---------
 examples/example_lesson_planner.glom  |   45 +++++++--------
 examples/example_project_manager.glom |   45 +++++++--------
 examples/example_smallbusiness.glom   |   45 +++++++--------
 glom/glom_document.dtd                |   95 ++++++++++++++++++---------------
 glom/libglom/document/document.cc     |   12 ++++-
 tests/dtd/test_example_sqlite         |    4 --
 tests/dtd/test_file_validation.sh     |    8 +++
 10 files changed, 154 insertions(+), 151 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index a44c6ac..566712c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
 2009-12-10  Murray Cumming  <murrayc murrayc com>
 
+	Tests: Validate all examples against the DTD, and correct the DTD.
+
+	* tests/dtd/test_example_sqlite: Renamed to test_file_validation.sh.
+	* glom/Makefile_tests.am: Adapted.
+	* glom/libglom/document/document.cc: save_before(): Correct the saving 
+	of group privileges so they are really inside the group nodes. Avoid 
+	saving unnamed groups, as seen in the example files.
+	* glom/glom_document.dtd: Several corrections to fix the validation of 
+	the example files, though I don't like that DTDs don't seem to give 
+	us any way to say that the sequence of child elements is irrelevant. 
+	I don't like enforcing the sequence.
+
+2009-12-10  Murray Cumming  <murrayc murrayc com>
+
 	Fix distcheck.
 
 	* Makefile.am:
diff --git a/Makefile_tests.am b/Makefile_tests.am
index 0843136..f753c3f 100644
--- a/Makefile_tests.am
+++ b/Makefile_tests.am
@@ -33,7 +33,7 @@ check_PROGRAMS =						\
 
 TESTS =	tests/test_parsing_time	\
 	tests/test_signal_reemit \
-        tests/dtd/test_example_sqlite \
+        tests/dtd/test_file_validation.sh \
 	tests/test_load_python_library \
 	tests/test_python_module \
 	tests/test_python_execute_func \
@@ -43,7 +43,7 @@ TESTS =	tests/test_parsing_time	\
 
 # We also set this in Makefile.am, with +=, 
 # but this is the first use, where we must use =
-dist_noinst_SCRIPTS = tests/dtd/test_example_sqlite
+dist_noinst_SCRIPTS = tests/dtd/test_file_validation.sh
 
 #TESTS_ENVIRONMENT=which valgrind && valgrind --tool=memcheck --leak-check=full --leak-resolution=high --trace-children=yes --num-callers=30
 
diff --git a/examples/example_film_manager.glom b/examples/example_film_manager.glom
index b5c8740..c39c479 100644
--- a/examples/example_film_manager.glom
+++ b/examples/example_film_manager.glom
@@ -2816,7 +2816,7 @@ else:
     <print_layouts/>
   </table>
   <groups><!--These are only used when recreating a database from an example file. The actual access-control is on the server, of course.-->
-    <group/>
+    <group name="accounts">
     <table_privs table_name="accommodation" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
     <table_privs table_name="cars" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
     <table_privs table_name="cast" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
@@ -2840,7 +2840,8 @@ else:
     <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
     <table_privs table_name="teams" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
     <table_privs table_name="test" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <group name="accounts"/>
+    </group>
+    <group name="glom_developer" developer="true">
     <table_privs table_name="accommodation" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
     <table_privs table_name="cars" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
     <table_privs table_name="cast" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
@@ -2864,31 +2865,8 @@ else:
     <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
     <table_privs table_name="teams" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
     <table_privs table_name="test" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <group name="glom_developer" developer="true"/>
-    <table_privs table_name="accommodation" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="cars" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="cast" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="companies" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="crew" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="deliveries" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="departments" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="equipment" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="glom_system_preferences" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="journeys" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="locations" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="products" priv_view="true"/>
-    <table_privs table_name="roles" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="scene_cast" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="scene_crew" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="scene_equipment" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="scenes" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="teams" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <table_privs table_name="test" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <group name="personnel_department"/>
+    </group>
+    <group name="personnel_department">
     <table_privs table_name="accommodation" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
     <table_privs table_name="cars" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
     <table_privs table_name="cast" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
@@ -2912,5 +2890,6 @@ else:
     <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
     <table_privs table_name="teams" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
     <table_privs table_name="test" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
+    </group>
   </groups>
   <library_modules/></glom_document>
diff --git a/examples/example_lesson_planner.glom b/examples/example_lesson_planner.glom
index 6e7b54c..ef92245 100644
--- a/examples/example_lesson_planner.glom
+++ b/examples/example_lesson_planner.glom
@@ -1758,29 +1758,26 @@ if __name__ == "__main__":
     <print_layouts/>
   </table>
   <groups><!--These are only used when recreating a database from an example file. The actual access-control is on the server, of course.-->
-    <group/>
-    <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="products" priv_view="true"/>
-    <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <group name="accounts"/>
-    <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="products" priv_view="true"/>
-    <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <group name="glom_developer" developer="true"/>
-    <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="products" priv_view="true"/>
-    <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <group name="personnel_department"/>
-    <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="products" priv_view="true"/>
-    <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
+    <group name="accounts">
+      <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="products" priv_view="true"/>
+      <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
+    </group>
+    <group name="glom_developer" developer="true">
+      <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="products" priv_view="true"/>
+      <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
+    </group>
+    <group name="personnel_department">
+      <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="products" priv_view="true"/>
+      <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
+    </group>
   </groups>
   <library_modules/></glom_document>
diff --git a/examples/example_project_manager.glom b/examples/example_project_manager.glom
index b55f35d..d768c18 100644
--- a/examples/example_project_manager.glom
+++ b/examples/example_project_manager.glom
@@ -1232,29 +1232,26 @@ if __name__ == "__main__":
     <print_layouts/>
   </table>
   <groups><!--These are only used when recreating a database from an example file. The actual access-control is on the server, of course.-->
-    <group/>
-    <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="products" priv_view="true"/>
-    <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <group name="accounts"/>
-    <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="products" priv_view="true"/>
-    <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <group name="glom_developer" developer="true"/>
-    <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="products" priv_view="true"/>
-    <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <group name="personnel_department"/>
-    <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="products" priv_view="true"/>
-    <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
+    <group name="accounts">
+      <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="products" priv_view="true"/>
+      <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
+    </group>
+    <group name="glom_developer" developer="true">
+      <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="products" priv_view="true"/>
+      <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
+    </group>
+    <group name="personnel_department">
+      <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="products" priv_view="true"/>
+      <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
+    </group>
   </groups>
   <library_modules/></glom_document>
diff --git a/examples/example_smallbusiness.glom b/examples/example_smallbusiness.glom
index 95341af..11e9174 100644
--- a/examples/example_smallbusiness.glom
+++ b/examples/example_smallbusiness.glom
@@ -1474,29 +1474,26 @@ if __name__ == "__main__":
     <print_layouts/>
   </table>
   <groups><!--These are only used when recreating a database from an example file. The actual access-control is on the server, of course.-->
-    <group/>
-    <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="products" priv_view="true"/>
-    <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <group name="accounts"/>
-    <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="products" priv_view="true"/>
-    <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <group name="glom_developer" developer="true"/>
-    <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="products" priv_view="true"/>
-    <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
-    <group name="personnel_department"/>
-    <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
-    <table_privs table_name="products" priv_view="true"/>
-    <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
+    <group name="accounts">
+      <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="products" priv_view="true"/>
+      <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
+    </group>
+    <group name="glom_developer" developer="true">
+      <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="products" priv_view="true"/>
+      <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
+    </group>
+    <group name="personnel_department">
+      <table_privs table_name="contacts" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoice_lines" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="invoices" priv_view="true" priv_edit="true"/>
+      <table_privs table_name="products" priv_view="true"/>
+      <table_privs table_name="staff" priv_view="true" priv_edit="true" priv_create="true" priv_delete="true"/>
+    </group>
   </groups>
   <library_modules/></glom_document>
diff --git a/glom/glom_document.dtd b/glom/glom_document.dtd
index 43680bf..4f2a551 100644
--- a/glom/glom_document.dtd
+++ b/glom/glom_document.dtd
@@ -48,7 +48,7 @@ TODO: Add 'title_singular' element.
       However, these are just initial permissions for examples. The real permissions are 
       always in the database.
 -->
-    <!ELEMENT groups (group|table_privs)*>
+    <!ELEMENT groups (group*)>
     <!ATTLIST groups>
 
 <!-- The group node specifies a group of users and lists the permissions for that group for each table.
@@ -57,7 +57,7 @@ TODO: Add 'title_singular' element.
      name: The name of this group of users.
      developer: Whether users in this group may use the developer features in Glom to change the database.
 -->
-    <!ELEMENT group EMPTY>
+    <!ELEMENT group (table_privs*)>
     <!ATTLIST group
         name CDATA #REQUIRED
         developer (true|false) "false">
@@ -89,7 +89,7 @@ TODO: Add 'title_singular' element.
   default: can specify that the table should be opened when the file is opened. Only one table should have default=true.
   example_rows: deprecated in 1.6 (and support removed in 1.10) - use the child node instead.
 -->
-    <!ELEMENT table (title_singular?, example_rows?, fields+, relationships?, data_layouts+, reports?, print_layouts?, trans_set?)>
+    <!ELEMENT table (title_singular?, example_rows?, trans_set?, fields+, relationships?, data_layouts+, reports?, print_layouts?)>
     <!ATTLIST table
         name CDATA #REQUIRED
         title CDATA #IMPLIED
@@ -100,14 +100,19 @@ TODO: Add 'title_singular' element.
 
 <!-- example_rows are comma separated lists of data (in the child text node) to load into the table 
      when it is first created. -->
-    <!ELEMENT example_rows ANY>
-    <!ATTLIST example_rows>
+    <!ELEMENT example_rows (example_row*)>
+
+    <!ELEMENT example_row (value*)>
+
+    <!ELEMENT value (#PCDATA)>
+    <!ATTLIST value
+        column CDATA #REQUIRED>
 
 <!-- relationships describe connections between databases. -->
 
     <!ELEMENT relationships (relationship*)>
     
-    <!ELEMENT relationship ANY>
+    <!ELEMENT relationship (trans_set?)>
     <!ATTLIST relationship
         name CDATA #REQUIRED
         title CDATA #IMPLIED
@@ -129,9 +134,9 @@ TODO: Add 'title_singular' element.
   default_value: New records will have this value in this field when they are first created.
   calculation: deprecated - use the child node instead.
 -->
-    <!ELEMENT fields (field | field_view)*>
+    <!ELEMENT fields (field*)>
 
-    <!ELEMENT field (field_lookup|calculation|formatting|trans_set)*>
+    <!ELEMENT field (calculation?, field_lookup?, formatting?, trans_set?)>
     <!ATTLIST field
         name CDATA #REQUIRED
         type CDATA #IMPLIED
@@ -156,7 +161,7 @@ TODO: Add 'title_singular' element.
   since normal text boxes are relatively simple. The choices_* options are for defining the custom choice
   boxes. -->
 
-    <!ELEMENT formatting ANY>
+    <!ELEMENT formatting (custom_choice_list*)>
     <!ATTLIST formatting
         format_thousands_separator (true|false) "true"
         format_text_multiline (true|false) "true"
@@ -173,7 +178,7 @@ TODO: Add 'title_singular' element.
 <!-- A custom_choice is a drop down menu that can be selected (for example, Mrs., Mr., Ms., etc) from
   a set of options. -->
 
-    <!ELEMENT custom_choice_list (custom_choice)*>
+    <!ELEMENT custom_choice_list (custom_choice*)>
     <!ATTLIST custom_choice_list>
 
     <!ELEMENT custom_choice EMPTY>
@@ -182,7 +187,7 @@ TODO: Add 'title_singular' element.
 
 <!-- The calculation node specifies python code that should be used to 
      calculate a value for this field. They python code is in a child text node. -->
-    <!ELEMENT calculation ANY>
+    <!ELEMENT calculation (#PCDATA)>
     <!ATTLIST calculation>
 
 <!-- data layouts determine the order of items and sorting of the fields. There are many
@@ -191,21 +196,20 @@ TODO: Add 'title_singular' element.
   on the grouping subnodes, which is the number of columns wide the element should be. 
   The name of the data_layout will be either "list" or "details".-->
 
-    <!ELEMENT data_layouts (data_layout_details | data_layout_list | data_layout)* >
+    <!ELEMENT data_layouts (data_layout*) >
 
     <!ELEMENT data_layout (data_layout_groups)>
     <!ATTLIST data_layout
         name CDATA #REQUIRED
         parent_table CDATA #IMPLIED>
 
-    <!ELEMENT data_layout_groups (data_layout_group)*>
+    <!ELEMENT data_layout_groups (data_layout_group*)>
     <!ATTLIST data_layout_groups>
 
 <!-- A data_layout_group is just a the setup of fields to be shown. It encapsulates everything else. -->
 
-    <!ELEMENT data_layout_group (trans_set | data_layout_group | data_layout_item | data_layout_portal |
-        data_layout_item_groupby | data_layout_button | data_layout_notebook | data_layout_item_header | 
-        trans_set | data_layout_text)*>
+    <!-- TODO: The comma separator specifies a fixed child node sequence, but we don't want to enforce that. -->
+    <!ELEMENT data_layout_group (trans_set?, (data_layout_group | data_layout_item | data_layout_portal | data_layout_calendar_portal | data_layout_item_groupby | data_layout_button | data_layout_notebook | data_layout_item_header | data_layout_text)*)>
     <!ATTLIST data_layout_group
         name CDATA #IMPLIED
         title CDATA #IMPLIED
@@ -214,7 +218,7 @@ TODO: Add 'title_singular' element.
 
 <!-- A data_layout_notebook is the tabbed display of tables in the glom interface. -->
 
-    <!ELEMENT data_layout_notebook (data_layout_group|data_layout_portal)*>
+    <!ELEMENT data_layout_notebook (data_layout_group*, data_layout_portal*)>
     <!ATTLIST data_layout_notebook
         name CDATA #REQUIRED
         columns_count CDATA #IMPLIED
@@ -223,9 +227,7 @@ TODO: Add 'title_singular' element.
 
 <!-- A data_layout_item_groupby is a data_layout_group that sorts -->
 
-    <!ELEMENT data_layout_item_groupby (trans_set | groupby | sortby | data_layout_group | data_layout_item |
-        data_layout_portal | data_layout_button | data_layout_item_groupby | secondary_fields | 
-        data_layout_item_summary | data_layout_item_verticalgroup)*>
+    <!ELEMENT data_layout_item_groupby (trans_set?, groupby?, sortby?, (data_layout_group |  data_layout_item | data_layout_portal | data_layout_calendar_portal | data_layout_button | data_layout_item_groupby |  secondary_fields | data_layout_item_summary | data_layout_item_verticalgroup)*)>
     <!ATTLIST data_layout_item_groupby
         name CDATA #IMPLIED
         title CDATA #IMPLIED
@@ -235,7 +237,7 @@ TODO: Add 'title_singular' element.
 
 <!-- data_layout_text and text are for displaying text. -->
 
-    <!ELEMENT data_layout_text (formatting | text)*>
+    <!ELEMENT data_layout_text (formatting?, text?)>
     <!ATTLIST data_layout_text
         sequence CDATA #IMPLIED>
 
@@ -245,12 +247,12 @@ TODO: Add 'title_singular' element.
         
 <!-- sortby describes what a data_layout_item_groupby sorts by. -->
 
-    <!ELEMENT sortby (data_layout_item)*>
+    <!ELEMENT sortby (data_layout_item*)>
     <!ATTLIST sortby>
     
 <!-- data_layout_item_verticalgroup is used to display a vertical group of fields. -->
 
-    <!ELEMENT data_layout_item_verticalgroup (data_layout_item)*>
+    <!ELEMENT data_layout_item_verticalgroup (data_layout_item*)>
     <!ATTLIST data_layout_item_verticalgroup
         name CDATA #IMPLIED
         columns_count CDATA #IMPLIED
@@ -259,13 +261,9 @@ TODO: Add 'title_singular' element.
 <!-- data_layout_item_summary and data_layout_item_fieldsummary summarize other
   fields. A good example of this is the total price in example_smallbusiness.glom. -->
 
-    <!ELEMENT data_layout_item_summary (data_layout_item_fieldsummary)*>
-    <!ATTLIST data_layout_item_summary
-        name CDATA #REQUIRED
-        columns_count CDATA #REQUIRED
-        sequence CDATA #IMPLIED>
+    <!ELEMENT data_layout_item_summary (data_layout_item_fieldsummary*)>
 
-    <!ELEMENT data_layout_item_fieldsummary (formatting)>
+    <!ELEMENT data_layout_item_fieldsummary (formatting?)>
     <!ATTLIST data_layout_item_fieldsummary
         name CDATA #REQUIRED
         editable (true|false) "false"
@@ -275,7 +273,7 @@ TODO: Add 'title_singular' element.
         
 <!-- groupby is used to determine how data_layout_item_groupby items group. -->
 
-    <!ELEMENT groupby (formatting|title_custom)*>
+    <!ELEMENT groupby (formatting?, title_custom?)>
     <!ATTLIST groupby
         name CDATA #REQUIRED
         editable (true|false) "false"
@@ -284,7 +282,7 @@ TODO: Add 'title_singular' element.
 
 <!-- secondary fields are fields derived from other fields - this is a list of them. -->
 
-    <!ELEMENT secondary_fields (data_layout_group)>
+    <!ELEMENT secondary_fields (data_layout_group*)>
     <!ATTLIST secondary_fields>
 
 
@@ -302,7 +300,7 @@ TODO: Add 'title_singular' element.
 <!-- A data_layout_item is a single entry in the display formatting, which tells how a single
   field is displayed. -->
 
-    <!ELEMENT data_layout_item (formatting|title_custom)* >
+    <!ELEMENT data_layout_item (formatting?, title_custom?) >
     <!ATTLIST data_layout_item
         name CDATA #REQUIRED
         relationship CDATA #IMPLIED
@@ -317,7 +315,7 @@ TODO: Add 'title_singular' element.
 <!-- A data_layout_item_header is the items that go at the very top of the database (e.g. the
   organization name and logo in example_film_manager.glom). -->
 
-    <!ELEMENT data_layout_item_header (data_layout_item)*>
+    <!ELEMENT data_layout_item_header (data_layout_item*)>
     <!ATTLIST data_layout_item_header
         name CDATA #IMPLIED
         columns_count CDATA #IMPLIED
@@ -334,12 +332,12 @@ TODO: Add 'title_singular' element.
 
 <!-- A script node is used to embed python code into the custom button. -->
 
-    <!ELEMENT script ANY>
+    <!ELEMENT script (#PCDATA)>
     <!ATTLIST script>
     
 <!-- A title_custom is used to give a different name next to a field than normal. -->
 
-    <!ELEMENT title_custom ANY>
+    <!ELEMENT title_custom (trans_set?)>
     <!ATTLIST title_custom
         title CDATA #IMPLIED
         use_custom (true|false) "true">
@@ -347,7 +345,7 @@ TODO: Add 'title_singular' element.
 <!-- A data_layout_portal is the essential information, a short and quick list of values
   that are probably of interest to others (e.g. contact information, name, etc). -->
 
-    <!ELEMENT data_layout_portal (portal_navigation_relationship | data_layout_item)* >
+    <!ELEMENT data_layout_portal (portal_navigation_relationship?, data_layout_item*) >
     <!ATTLIST data_layout_portal
         name CDATA #IMPLIED
         relationship CDATA #REQUIRED
@@ -355,6 +353,15 @@ TODO: Add 'title_singular' element.
         hide CDATA #IMPLIED
         columns_count CDATA #IMPLIED>
 
+ <!ELEMENT data_layout_calendar_portal (portal_navigation_relationship?, data_layout_item*) >
+    <!ATTLIST data_layout_calendar_portal
+        name CDATA #IMPLIED
+        relationship CDATA #REQUIRED
+        date_field CDATA #REQUIRED
+        sequence CDATA #IMPLIED
+        hide CDATA #IMPLIED
+        columns_count CDATA #IMPLIED>
+
 <!-- portal_navigation_relationship determines what happens when the user 
      activates a row in a related records portal.
      portal_navigation_relationship: "automatic", "specific" or "none".
@@ -363,7 +370,7 @@ TODO: Add 'title_singular' element.
      related_relationship: If portal_navigation_relationship is "specific" then 
      this may be a related (to relationship) relationship to which to navigate. -->
 
-    <!ELEMENT portal_navigation_relationship ANY>
+    <!ELEMENT portal_navigation_relationship EMPTY>
     <!ATTLIST portal_navigation_relationship
         navigation_type CDATA #IMPLIED
         relationship CDATA #IMPLIED
@@ -373,17 +380,17 @@ TODO: Add 'title_singular' element.
   distill a larger database. data_report(s) is the old interface; use reports if you are
   writing a new XML document. -->
 
-    <!ELEMENT data_reports (data_report)*>
+    <!ELEMENT data_reports (data_report*)>
 
-    <!ELEMENT data_report (data_layout_groups)>
+    <!ELEMENT data_report (data_layout_groups*)>
     <!ATTLIST data_report
         name CDATA #REQUIRED
         title CDATA #REQUIRED>
 
-    <!ELEMENT reports (report)*>
+    <!ELEMENT reports (report*)>
     <!ATTLIST reports>
 
-    <!ELEMENT report (data_layout_groups|trans_set)*>
+    <!ELEMENT report (data_layout_groups*, trans_set?)>
     <!ATTLIST report
         name CDATA #REQUIRED
         title CDATA #IMPLIED
@@ -396,14 +403,14 @@ TODO: Add 'title_singular' element.
         name CDATA #REQUIRED
         parent_table CDATA #IMPLIED>
 
-    <!ELEMENT print_layout_groups (print_layout_group)*>
+    <!ELEMENT print_layout_groups (print_layout_group*)>
     <!ATTLIST print_layout_groups>
 
 
 <!-- The library_modules node contains python code that may be used in scripts and 
      calculations via the python import keyword. -->
 
-    <!ELEMENT library_modules ANY>
+    <!ELEMENT library_modules (module*)>
     <!ATTLIST library_modules>
 
 <!-- library_module nodes contain python code that may be used in scripts and 
@@ -411,7 +418,7 @@ TODO: Add 'title_singular' element.
      child text node.
      name: The name of the module, to be used with the python import command.
      script: Deprecated in Glom 1.12. The code of the python module. -->
-    <!ELEMENT module ANY>
+    <!ELEMENT module (#PCDATA)>
     <!ATTLIST module
         name CDATA #REQUIRED>
 
diff --git a/glom/libglom/document/document.cc b/glom/libglom/document/document.cc
index d064591..3b647a0 100644
--- a/glom/libglom/document/document.cc
+++ b/glom/libglom/document/document.cc
@@ -3538,14 +3538,22 @@ bool Document::save_before()
     {
       const GroupInfo& group_info = iter->second;
 
+      const Glib::ustring group_name = group_info.get_name();
+      if(group_name.empty())
+      {
+        //I saw this in at least one .glom file. murrayc.
+        std::cerr << "Document::save_before(): The group name is empty." << std::endl;
+        continue;
+      }
+
       xmlpp::Element* nodeGroup = nodeGroups->add_child(GLOM_NODE_GROUP);
-      set_node_attribute_value(nodeGroup, GLOM_ATTRIBUTE_NAME, group_info.get_name());
+      set_node_attribute_value(nodeGroup, GLOM_ATTRIBUTE_NAME, group_name);
       set_node_attribute_value_as_bool(nodeGroup, GLOM_ATTRIBUTE_DEVELOPER, group_info.m_developer);
 
       //The privileges for each table, for this group:
       for(GroupInfo::type_map_table_privileges::const_iterator iter = group_info.m_map_privileges.begin(); iter != group_info.m_map_privileges.end(); ++iter)
       {
-        xmlpp::Element* nodeTablePrivs = nodeGroups->add_child(GLOM_NODE_TABLE_PRIVS);
+        xmlpp::Element* nodeTablePrivs = nodeGroup->add_child(GLOM_NODE_TABLE_PRIVS);
 
         set_node_attribute_value(nodeTablePrivs, GLOM_ATTRIBUTE_TABLE_NAME, iter->first);
 
diff --git a/tests/dtd/test_file_validation.sh b/tests/dtd/test_file_validation.sh
new file mode 100755
index 0000000..64e596d
--- /dev/null
+++ b/tests/dtd/test_file_validation.sh
@@ -0,0 +1,8 @@
+#/bin/sh -e
+
+for x in $(find ${srcdir}/examples/ -name "*.glom")
+do
+  # echo Validating $x
+  xmllint --noout --dtdvalid ${srcdir}/glom/glom_document.dtd \
+    $x
+done



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