xmlxpathxsltxml-namespacesqnames

How should I resolve and compare two QNames using XPath for XSLT?


I want to test, within an XSLT document, whether an attribute value of type QName from the input XML is equal to another QName from the XSLT document. I want to evaluate each QName according to its parent document namespace declarations before the comparison.

So, the following XSLT...

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    exclude-result-prefixes="msxsl"
    xmlns:aTest="http://tempuri.org/Test"
>
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="@* | node()">
        <xsl:if test="/@name = 'aTest:a'">Success</xsl:if>
    </xsl:template>
</xsl:stylesheet>

...given the following input...

<?xml version="1.0" encoding="utf-8" ?>
<root
    xmlns:test="http://tempuri.org/Test"
    name="test:a"
></root>

...would produce "Success" (I know why it doesn't as is, but hopefully you see my intention).


Solution

  • You must compare the parts before and after the : separately. The namespace prefix before the : can be translated into the namespace URI by looking it up on the corresponding namespace axis:

    <xsl:stylesheet version="1.0" 
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:aTest="http://tempuri.org/Test">
      <xsl:template match="root">
        <xsl:variable name="v">aTest:a</xsl:variable>
        <xsl:if test="namespace::*[local-name()=substring-before(current()/@name,':')] =
                      document('')/*/namespace::*[local-name()=substring-before($v,':')]
                  and substring-after(@name,':') = substring-after($v,':')">Success</xsl:if>
      </xsl:template>
    </xsl:stylesheet>
    

    If, for some reason, you cannot invoke the function document(''), you can simply write the namespace URI and the local name in the condition:

    namespace::*[local-name()=substring-before(current()/@name,':')] =
    'http://tempuri.org/Test'
    and substring-after(@name,':') = 'a'
    

    (XSLT 1.0)