Your XSLT approach is way too complicated. XSLT is verbose, but not that verbose.
A few hints.
Use proper namespace declarations. If most of your output needs to be in a certain namespace, put your stylesheet into that namespace by default. Declare:
xmlns="http://www.isotc211.org/2005/gmd"
at the top level of your XSLT and your entire output will be in that namespace automatically except for nodes you declare otherwise.
Don't use
<xsl:element>
if you want to create elements with a fixed name. Just write out the elements you want to create.<xsl:element name="gmd:MD_Metadata"> </xsl:element>
is equivalent to:
<MD_Metadata> </MD_Metadata>
if you used a default namespace like indicated above.
The same goes for
<xsl:attribute>
. Just write it out.<xsl:element name="gmd:LanguageCode"> <xsl:attribute name="codeList">./resource/codeList.xml#LanguageCode</xsl:attribute> </xsl:element>
is
<LanguageCode codeList="./resource/codeList.xml#LanguageCode"> </LanguageCode>
Use attribute value templates to fill attributes with calculated values:
<LanguageCode codeListValue="{.}" />
note the curly braces, into which you can put any XPath expression.
Don't use
<xsl:for-each>
at all. Write templates and use<xsl:apply-templates>
. Try to write short templates instead of cramming everything into one big<xsl:template match="/">
.
This entire use-case is perfect for a "pull-style" approach.
- You don't really want to change much of your input. From all I can see, differences between v3 and v5 are marginal.
- Base your stylesheet on the identity template, handle only those cases where you actually need to make a change to the input.
- Think: "If I find such a node is in the input, how should the output look like?".
- Write a template accordingly.
- Handle all nesting/recursion by calling
<xsl:apply-templates>
. - It helps thinking your of input XML flowing through the stylesheet, like through a sieve. You don't make your stylesheet do stuff, you only set up case handlers.
This stylesheet is a good start:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:gco="http://www.isotc211.org/schemas/2005/gco"
xmlns:gmd="http://www.isotc211.org/schemas/2005/gmd"
xmlns="http://www.isotc211.org/schemas/2005/gmd"
>
<xsl:output indent="yes" encoding="utf-8" />
<!-- default: all input nodes are copied as they are (identity template) -->
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<!-- override: MD_Metadata needs to be rebuilt -->
<xsl:template match="gmd:MD_Metadata">
<xsl:copy>
<xsl:apply-templates select="@*" />
<!-- handle fileIdentifier and language first -->
<xsl:apply-templates select="gmd:fileIdentifier | gmd:language" />
<!-- now a few additions that are not in the source -->
<characterSet>
<MD_CharacterSetCode codeList="./resource/codeList.xml#MD_CharacterSetCode" codeListValue="utf8" />
</characterSet>
<parentIdentifier>
<gco:CharacterString />
</parentIdentifier>
<hierarchyLevel>
<MD_ScopeCode codeList="./resource/codeList.xml#MD_ScopeCode" codeListValue="" />
</hierarchyLevel>
<!-- now handle the rest of the contents -->
<xsl:apply-templates select="node()[not(
self::gmd:fileIdentifier or
self::gmd:language
)]" />
</xsl:copy>
</xsl:template>
<!-- override: the CharacterString beneath language becomes a LanguageCode -->
<xsl:template match="gmd:language/gco:CharacterString">
<LanguageCode codeList="./resource/codeList.xml#LanguageCode" codeListValue="{.}">
<xsl:value-of select="." />
</LanguageCode>
</xsl:template>
<!-- add more overrides... -->
</xsl:stylesheet>
Note how the entire XSLT above does not concern itself with iteration or nesting. <xsl:apply-templates>
always redirects to the identity template (or an override template you supplied). This way you need to build specific templates only for stuff that needs to change on its way from input to output.
The output looks like this:
<MD_Metadata xsi:schemaLocation="http://www.isotc211.org/schemas/2005/gmd/gmd.xsd" xmlns="http://www.isotc211.org/schemas/2005/gmd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gco="http://www.isotc211.org/schemas/2005/gco" xmlns:gml="http://www.opengis.net/gml" xmlns:xlink="http://www.w3.org/1999/xlink">
<fileIdentifier>
<gco:CharacterString>b0101011_Vincolo</gco:CharacterString>
</fileIdentifier>
<!-- ... and so on -->
</MD_Metadata>
If necessary, use empty templates to suppress unwanted output:
<xsl:template match="gmd:foo" />
<xsl:template match="gmd:bar" />
If you have a definitive list of changes from v3 to v5 you also have a list of override templates to create.