Scala script
In my day job recently I found a way to sneak some Scala code into the project. I developed a datamodel module containing POJOs and JiBX bindings to marshal Objects into XML documents conforming to our XML schema. Some elements were constrained by enumerations, located either in the schema documents themselves or elsewhere in SQL dataload scripts. I stored these enumerations as properties files, so they could be easily edited when enumeration values changed.
Obviously this solution is not perfect. It violates the DRY (Don’t Repeat Yourself) principle, and enumeration value updates are likely to be forgotten. I decided to write a script that pulls the enumeration values out of their original locations and generates the properties files fresh, to ease maintainability. Scala includes the ability to run as a script, and its XML support is a lot better than Java’s, so I picked it.
Here’s an edited version of the script:
import io.Source import java.io.{FileWriter, PrintWriter} import xml.{Node, Elem, XML} /** * This script will extract enumerations from schema and dataload files and write corresponding properties files. */ val schemaDir = "C:\\Schemas\\ixm-ws-5.5\\xsd\\" val outputDir = "C:\\testharness\\datamodel\\src\\conf\\" // Get the enumerations out of jxdm.xsd var xsd = XML.loadFile(schemaDir + "subset\\jxdm\\3.0.3\\jxdm.xsd") extractEnumeration(xsd, "ActivityType.properties", "element", "ActivityTypeText", {node => (node \ "@value").text}) extractEnumeration(xsd, "DocumentStatus.properties", "element", "StatusText", {node => (node \ "@value").text}) // Get the enumerations out of ansi-nist.xsd xsd = XML.loadFile(schemaDir + "subset\\niem\\ansi-nist\\2.0\\ansi-nist.xsd") extractEnumeration(xsd, "ScaleUnits.properties", "simpleType", "SLCCodeSimpleType", {node => (node \\ "documentation").text}) def extractEnumeration(xsd: Elem, propFileName: String, elementType: String, elementName: String, p: (Node) => String) { val out = new PrintWriter(outputDir + propFileName) xsd \\ elementType filter(node => (node \ "@name").text == elementName) foreach{(element) => element \\ "enumeration" foreach{(enumeration) => val value = (enumeration \ "@value").text val key = p(enumeration).trim.replace(" ", "\\ ") out.println(key + "=" + value) } } out.flush out.close }
The neatest part about this code is the last parameter to the extractEnumeration function: a function converting a Node to a String. Some of the enumeration values appear in nodes with the attribute “value” and some appear in nodes called “documentation”. I created closures that extracted the text out of each type of node and sent those functions as parameters to the extractEnumeration method. In Java I’d have to create a switch statement for each type of enumeration value extract and sent in a parameter to indicate which option to use. This way, when a new value extraction function is needed, we don’t have to touch the extractEnumeration function at all. I could have assigned the two closures to objects and reused them for all the extractEnumeration calls, but I thought this way made the code a little more readable.
My next idea for this was to integrate this script as an optional step in our maven build. But this didn’t go so well. Full details in the next post!