blob: ad7998a9ca087caa829796b2e5eee3127647a57d [file] [log] [blame]
------
XML table mapping
------
XML table mapping
Since XML files are hierarical and MetaModel tables are tabular, you need
to do some mapping. MetaModel provides a mapping model that is XPath based,
with a few slight modifications.
Assume we have the following XML document:
+-------------------------------+
<?xml version="1.0" encoding="UTF-8"?>
<root>
<organization type="governmental">
<name>Company A</name>
<employees>
<employee>
<name>John Doe</name>
<gender>M</gender>
</employee>
<employee>
<name>Jane Doe</name>
<gender>F</gender>
</employee>
</employees>
</organization>
<organization type="company">
<name>Company B</name>
<employees>
<employee>
<name>Peter</name>
<gender>M</gender>
</employee>
<employee>
<name>Bob</name>
<gender>M</gender>
</employee>
</employees>
</organization>
</root>
+-------------------------------+
Now imagine that you want to have a table of employee names and gender information,
and another table with company name and type information. We define our DataContext and
those tables like this:
+-------------------------------+
XmlSaxTableDef employeeTableDef = new XmlSaxTableDef(
"/root/organization/employees/employee",
new String[] {
"/root/organization/employees/employee/name",
"/root/organization/employees/employee/gender"
}
);
XmlSaxTableDef organizationTableDef = new XmlSaxTableDef(
"/root/organization",
new String[] {
"/root/organization/name",
"/root/organization@type"
}
);
DataContext dc = new XmlSaxDataContext(
new File("my_file.xml"), employeeTableDef, organizationTableDef);
+-------------------------------+
As you see, we simply provide some XPath expressions to 1) define the record scope and 2) define
paths of individual values (or rather - the column definitions). If you query those tables,
you will get datasets like these:
Table: /employee
*--------------------+-----------------+-----------------+
| <<row_id>> | <</name>> | <</gender>> |
*--------------------+-----------------+-----------------+
| 0 | John Doe | M |
*--------------------+-----------------+-----------------+
| 1 | Jane Doe | F |
*--------------------+-----------------+-----------------+
| 2 | Peter | M |
*--------------------+-----------------+-----------------+
| 3 | Bob | M |
*--------------------+-----------------+-----------------+
Table: /organization
*--------------------+-----------------+-----------------+
| <<row_id>> | <</name>> | <<@type>> |
*--------------------+-----------------+-----------------+
| 0 | Company A | governmental |
*--------------------+-----------------+-----------------+
| 1 | Company B | company |
*--------------------+-----------------+-----------------+
This is nice, but you might be thinking: How can I then join these tables? There doesn't seem
to be any cross-reference value that we can join or perform lookups by.
To solve this issue, MetaModel provides a modification for XPath, the index(...) function. Say
we want to add the organization's id to the employee table (as a foreign key). To archieve that,
we will need this modified employee table definition (notice the third value XPath expression):
+-------------------------------+
XmlSaxTableDef employeeTableDef = new XmlSaxTableDef(
"/root/organization/employees/employee",
new String[] {
"/root/organization/employees/employee/name",
"/root/organization/employees/employee/gender",
"index(/root/organization)"
}
);
+-------------------------------+
Now if you query the employees table, this will be your result:
*--------------------+-----------------+-----------------+-------------------------------+
| <<row_id>> | <</name>> | <</gender>> | <<index(/root/organization)>> |
*--------------------+-----------------+-----------------+-------------------------------+
| 0 | John Doe | M | 0 |
*--------------------+-----------------+-----------------+-------------------------------+
| 1 | Jane Doe | F | 0 |
*--------------------+-----------------+-----------------+-------------------------------+
| 2 | Peter | M | 1 |
*--------------------+-----------------+-----------------+-------------------------------+
| 3 | Bob | M | 1 |
*--------------------+-----------------+-----------------+-------------------------------+
Moving on, you will be able to define both joins and lookups using this foreign key. For example:
+-------------------------------+
Column fk = employeeTable.getColumnByName("index(/root/organization)");
Column empName = employeeTable.getColumnByName("/name");
Column orgId = organizationTable.getColumnByName("row_id");
Column orgName = organizationTable.getColumnByName("/name");
Query q = dc.query().from(employeeTable)
.innerJoin(organizationTable).on(fk, orgId)
.select(empName).as("employee")
.select(orgName).as("company").toQuery();
DataSet ds = dc.executeQuery(q);
+-------------------------------+
The contents of this queried dataset will now be:
*-----------------+-----------------+
| <<employee>> | <<company>> |
*-----------------+-----------------+
| John Doe | Company A |
*-----------------+-----------------+
| Jane Doe | Company A |
*-----------------+-----------------+
| Peter | Company B |
*-----------------+-----------------+
| Bob | Company B |
*-----------------+-----------------+