Structure in a Flat World

Adding Structure to Flat XML Documents

A friend recently was wondering how to convert a flat document structure to a more structured form.

The type of flat structure is shown in the diagram below:

The deptNo and deptName fields repeat for each employee in the department.

This would be better represented as a structured format like the one shown below:

 

Note that the department details are now represented once per department and employees appear in a sequence called emp.  This is a more natural representation and easier to manipulate elsewhere.

So the question is, how do I get from the flat schema to the structured schema?

The answer lies in the preceding-sibling and following-sibling XPath axis.

To get just the first time a department appears we select all the entries that do not have the same deptNo earlier in the document using this XPath expression:

<xsl:for-each select="/ns1:collection/ns1:entry[not(ns1:deptNo = preceding-sibling::ns1:entry/ns1:deptNo)]">

Within the first occurrence of a department we then set a variable to hold the department number:

<xsl:variable name="DeptNo" select="ns1:deptNo"/>

Within the department we then put in the employee included in the current node.  We then select all the other entries that have the same department number and add their employee details by using the following XPath expression:

<xsl:for-each select="following-sibling::ns1:entry[ns1:deptNo = $DeptNo]">

A sample JDeveloper project to test this is available here.

Comments:

If you have the luxury of using XSLT 2, the for-each-group construct provides a simpler way to achieve this result:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:flat="http://antony.blog/flat"
xmlns:struct="http://antony.blog/structured">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<struct:collection>
<xsl:for-each-group select="//flat:entry" group-by="flat:deptNo">
<struct:dept>
<struct:deptNo>
<xsl:value-of select="current-grouping-key()"/>
</struct:deptNo>
<struct:deptName>
<xsl:value-of select="flat:deptName"/>
</struct:deptName>
<struct:emps>
<xsl:for-each select="current-group()">
<struct:emp>
<struct:empNo>
<xsl:value-of select="flat:empNo"/>
</struct:empNo>
<struct:empName>
<xsl:value-of select="flat:empName"/>
</struct:empName>
</struct:emp>
</xsl:for-each>
</struct:emps>
</struct:dept>
</xsl:for-each-group>
</struct:collection>
</xsl:template>
</xsl:stylesheet>

Posted by Geoff on October 19, 2011 at 08:25 PM MDT #

Post a Comment:
Comments are closed for this entry.
About

Musings on Fusion Middleware and SOA Picture of Antony Antony works with customers across the US and Canada in implementing SOA and other Fusion Middleware solutions. Antony is the co-author of the SOA Suite 11g Developers Cookbook, the SOA Suite 11g Developers Guide and the SOA Suite Developers Guide.

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today