Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safari XSLT engine loses namespace on attributes

I have an XSLT that matches certain attributes, and puts them in a different namespace. Here is a simplified version:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="urn:test:ns1"
    xmlns:ns2="urn:test:ns2">
    <xsl:output method="xml" indent="no" encoding="UTF-8"/>

    <!-- copy all nodes -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*[starts-with(local-name(), 'test-')]">
        <xsl:attribute name="ns2:{substring-after(local-name(), '-')}" namespace="urn:test:ns2">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

Here is some example input:

<?xml version="1.0" encoding="UTF-8" ?>
<hello-world
    xmlns="urn:test:ns1"
    xmlns:ns3="urn:test:ns3"
    rootAttr="stays in implicit namespace"
    ns3:passMe="stays in the ns3 namespace"
    test-someRootAttr="goes into the ns2 namespace, pulls up ns declaration">
    <test
        defaultAttr="stays in implicit namespace"
        test-someAttr="goes into the ns2 namespace"
        ns3:namedAttr="stays in the ns3 namespace">
        Something
    </test>
    <ns3:cat
        defaultAttr="stays in the implicit namespace"
        test-catName="goes into the ns2 namespace"
        ns3:namedAttr="stays in the ns3 namespace">
        a cat
    </ns3:cat>
</hello-world>

And here is the expected output:

<?xml version="1.0" encoding="UTF-8" ?>
<hello-world
    xmlns="urn:test:ns1"
    xmlns:ns2="urn:test:ns2"
    xmlns:ns3="urn:test:ns3"
    rootAttr="stays in implicit namespace"
    ns3:passMe="stays in the ns3 namespace"
    ns2:someRootAttr="goes into the ns2 namespace, pulls up ns declaration">
    <test
        defaultAttr="stays in implicit namespace"
        ns2:someAttr="goes into the ns2 namespace"
        ns3:namedAttr="stays in the ns3 namespace">
        Something
    </test>
    <ns3:cat
        defaultAttr="stays in the implicit namespace"
        ns2:catName="goes into the ns2 namespace"
        ns3:namedAttr="stays in the ns3 namespace">
        a cat
    </ns3:cat>
</hello-world>

This works fine on Chrome, Firefox, IE 9+, and Android. However on Safari, I get the following output instead:

<?xml version="1.0" encoding="UTF-8" ?>
<hello-world
    xmlns="urn:test:ns1"
    xmlns:ns3="urn:test:ns3"
    xmlns:ns2="urn:test:ns2"
    rootAttr="stays in implicit namespace"
    passMe="stays in the ns3 namespace"
    someRootAttr="goes into the ns2 namespace, pulls up ns declaration">
    <test
        defaultAttr="stays in implicit namespace" 
        someAttr="goes into the ns2 namespace" 
        namedAttr="stays in the ns3 namespace">
        Something
    </test>
    <ns3:cat
        defaultAttr="stays in the implicit namespace" 
        catName="goes into the ns2 namespace" 
        namedAttr="stays in the ns3 namespace">
        a cat
    </ns3:cat>
</hello-world>

Notice that the namespace declarations are correct, but the attributes are missing the desired namespace prefix.

All of this code is in a github project, which is built by TravisCI and uses Sauce Labs to test on different browser/OS combos.

Can I do something differently with my XSLT that would be a more correct way to accomplish this, that might work on all engines? Or is this just a bug in Safari? Any ideas for workarounds would be much appreciated.

like image 620
murrayju Avatar asked Oct 21 '15 18:10

murrayju


Video Answer


2 Answers

I think this is a bug. As a work around you could try to set the namespace you want as well on the xsl:attribute namespace="urn:test:ns2".

like image 82
Martin Honnen Avatar answered Oct 27 '22 05:10

Martin Honnen


Without any evidence to the contrary, this appears to be a bug in Safari. I've reported this to Apple (rdar://23207226), but so far haven't heard anything from them.

The only available workaround is to run the XSLT on some other engine (server side, or perhaps through a 3rd party javascript engine).

like image 30
murrayju Avatar answered Oct 27 '22 04:10

murrayju