Skip to content

Instantly share code, notes, and snippets.

@LegoStormtroopr
Created August 19, 2012 00:20
Show Gist options
  • Save LegoStormtroopr/3390504 to your computer and use it in GitHub Desktop.
Save LegoStormtroopr/3390504 to your computer and use it in GitHub Desktop.
Using XPath1.0 to resolve the correct implied value of an XML elements xml:lang attribute

About:

This is an XSLT Document that demonstrates how to determine the correct value for an xml:lang attribute for an element using only XPath 1.0.

Licence:

This code is all released directly into the Public Domain, but it would be swell if you could provide attribution.

Author:

Sam Spencer - theodore[dot]therone[at]gmail[dot]com

About the XPath

The XPath just below (and also on line 8 of xml_lang_xpath_resolver.xsl) can be used to find the correct value of an xml:lang attribute for a given element.

   ancestor-or-self::*[attribute::xml:lang][1]/@xml:lang

Broken down this (The decribed pieces at each stage are underlined using carets.

  1. Follows the tree back to the root, through all ancestors, and returns only those that have an xml:lang attribute.

     ancestor-or-self::*[attribute::xml:lang][1]/@xml:lang
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
  2. This list is returned in order going away the element we are searching from, so we grab the first (or closest element).

     ancestor-or-self::*[attribute::xml:lang][1]/@xml:lang
                                             ^^^
    
  3. Having the nearest element that has an xml:lang set, we than just return the value of its xml:lang attribute.

     ancestor-or-self::*[attribute::xml:lang][1]/@xml:lang
                                                ^^^^^^^^^^
    

About the XSL Transform

It will clone an XML document exactly and add the correct xml:lang tag into the document. In reality, this is probably not something that you would want to do, but this serves to demonstrate what the xml:lang attribute should be when processing an XML document. This is an extension of the XSLT Identity Template which can be read about here: http://www.xmlplease.com/xsltidentity.

<?xml version="1.0" encoding="utf-8"?>
<data>
<foo xml:lang="en">
<bar>
<tog xml:lang="fr">
<wel>
<vay xml:lang="sv"/>
</wel>
</tog>
<tog>
<wel>
<hut xml:lang="it"/>
</wel>
</tog>
<tog xml:lang=""/>
</bar>
</foo>
</data>
<?xml version="1.0" encoding="utf-8"?>
<data xml:lang="">
<foo xml:lang="en">
<bar xml:lang="en">
<tog xml:lang="fr">
<wel xml:lang="fr">
<vay xml:lang="sv"/>
</wel>
</tog>
<tog xml:lang="en">
<wel xml:lang="en">
<hut xml:lang="it"/>
</wel>
</tog>
<tog xml:lang=""/>
</bar>
</foo>
</data>
<?xml version="1.0" encoding="UTF-8"?>
<!-- View readme.md for more information -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:attribute name="xml:lang">
<xsl:value-of select="ancestor-or-self::*[attribute::xml:lang][1]/@xml:lang"/>
</xsl:attribute>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
@LegoStormtroopr
Copy link
Author

Ignore all of the prior changes, i just don't get Markdown.

@borsna
Copy link

borsna commented Aug 21, 2012

Excellent Sam!
Made this into an xQuery function:

(:~
 : Get the nearest xml:lang
 : @param   $node the node to get the xml:lang attribute from
 : @return  language code
 :)
declare function local:getLang($node as node()) as xs:string{
    xs:string($node/ancestor-or-self::*[attribute::xml:lang][1]/@xml:lang)
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment