XSLT to map EPP and automaton inputs
Here at Nominet, we have two interfaces to the registry database:
- The automaton, an email system which uses PGP signed lists of key-value pairs (KVPs), e.g:
operation: domain request key: auto-example.co.uk account-id: 1000001 dns0: ns0.auto-example.co.uk 96.152.146.245 dns1: ns1.auto-example.co.uk 96.152.146.246 1234::1234
- and EPP, an XML based system. The above request would essentially be written in XML as:
<epp> <create> <domain:create> <domain:name>auto-example.co.uk</domain:name> <domain:account> <domain:account-id>1000001</domain:account-id> </domain:account> <nameservers> <ns:create> <ns:name>ns0.auto-example.co.uk</ns:name> <ns:addr ip="v4">96.152.146.245</ns:addr> </ns:create> <ns:create> <ns:name>ns0.auto-example.co.uk</ns:name> <ns:addr ip="v4">96.152.146.246</ns:addr> <ns:addr ip="v6">1234::1234</ns:addr> </ns:create> </nameservers> </domain:create> </create> </epp>
These are two separate processes but basically do the same thing - they write to a database but with a different interface, so we were keen to use as much common code as possible in the system. One way to facilitate this is to use an XSL transformation (using hardware XML acceleration for performance) to convert the XML into KVPs.
Generally, the XSL for this looks like:
<xsl:template match="xml-element-name">key-name: <xsl:apply-templates/> <xsl:text>
</xsl:text> </xsl:template>
This tells the XSL processor “whenever you see xml-element-name write out the corresponding key-name and then process the rest of the element”. For leaf elements, processing the rest of the element will get you the XML value added to the output. The 
 adds a linebreak.
So, for example:
<xsl:template match="domain:name">key: <xsl:apply-templates/>
<xsl:text>
</xsl:text>
</xsl:template>
converts the
<domain:name>auto-example.co.uk</domain:name>
line in the EPP request into a corresponding KVP:
key:auto-example.co.uk
This is fairly straightforward for most fields in the requests. Dealing with nameserver fields is however a little more complicated as the KVPs need to be enumerated and the name and ip addresses need to be included in the same value. To do this, the XSL needs to output the ‘dns#: ‘ part when it encounters an <ns:create> element and then add the name and ip addresses when it encounters the child elements.
To find where the entry sits in the dns enumeration, it is necessary to use XPath within an <xsl:value-of> element to count the position of the <ns:create> amongst its sibling elements:
<xsl:template match="ns:create">dns<xsl:value-of select="position()-1"/>
<xsl:text>: </xsl:text>
<xsl:apply-templates/>
</xsl:template>
This works ok for nameservers until you consider that there is no restriction on the order of the ip addresses in the XML. The order of different elements in EPP requests is specified by the schema, but <ns:addr> elements are distinguished only by their attributes and there are no restrictions on the order. So, it is possible for an ipv6 address to be provided before the ipv4 address and the resultant KVP in the above example:
dns0: ns0.auto-example.co.uk 1234::1234 96.152.146.246
would confuse the KVP processing code. To get around this, we need to tell the XSL processor to go and find the ip addresses in the correct order when it finds the name. Again, we need to use XPath:
<xsl:template match="ns:name">
<!-- Add the name-->
<xsl:apply-templates/>
<!-- Go find the ip addresses-->
<xsl:if test=
"count(following-sibling::*[local-name()='addr' and @ip='v4']) > 0">
<xsl:text> </xsl:text>
<xsl:value-of select=
"following-sibling::*[local-name()='addr' and @ip='v4']"/>
</xsl:if>
<xsl:if test=
"count(following-sibling::*[local-name()='addr' and @ip='v6']) > 0">
<xsl:text> </xsl:text>
<xsl:value-of select=
"following-sibling::*[local-name()='addr' and @ip='v6']"/>
</xsl:if>
<xsl:text>
</xsl:text>
</xsl:template>
We don’t need to worry about the key for the KVP here as this has already been done at the <ns:create> element.
So, to find the ipv4 address, we count the number of following siblings with name *:addr and ip attribute of ‘v4‘. If there is one then add it’s value to the KVP.

(1 votes, average: 4 out of 5)
December 21st, 2007 at 10:09 am
Why not simply defining the order in a template for ?
dns
:


:
December 21st, 2007 at 10:10 am
It seems my XSLT code was not accepted by the blog engine :-)
Second try:
<xsl:template match=”ns:create”>
<xsl:text>dns</xsl:text>
<xsl:value-of select=”position()-1″/>
<xsl:text>: </xsl:text>
<xsl:apply-templates select=”ns:name”/>
<!– Process them in the order expected by the KVP engine –>
<xsl:apply-templates select=”ns:addr[@ip=’v4′]”/>
<xsl:apply-templates select=”ns:addr[@ip=’v6′]”/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match=”ns:name”>
<xsl:apply-templates/>
<xsl:text>: </xsl:text>
</xsl:template>
<xsl:template match=”ns:addr”>
<xsl:apply-templates/>
<xsl:text> </xsl:text>
</xsl:template>
January 2nd, 2008 at 7:50 am
Yes, that is neater. We need to get rid of the
<xsl:text>: </:text>
line in the “ns:name” match line, otherwise there are too many colons. Thanks.
January 9th, 2008 at 10:00 am
When the EPP comes off the test bed will it be SSL only or also still run a plain text version?
January 9th, 2008 at 10:43 am
The live version will be SSL only. We will continue to run the testbed alongside it indefinitely in both SSL and plain text.