I think that I have found an workaround :)
Instead of applying the transformation on a StreamSource object I am applying it on a DOMSource object and now the lookupNamespaceUri method works as expected.
Adrian.

Adrian Herscu wrote:
Hi Michael and thanks for the response.
Please see my comments between your lines.
Regards,
Adrian.

Michael Ludwig wrote:

    <gen:test func="lookupNamespaceUri">

Now what's wrong with <xsl:value-of select="namespace-uri()"/> ?
No need to call an extension function here.

To get the URIs for all the namespace nodes in scope, try:

    <xsl:for-each select="namespace::node()">
      <NS><xsl:value-of select="."/></NS>
    </xsl:for-each>


Please remember that this is just a simplified test case. My actual problem is traversing relational data structures with less XSL code.
 From the initial post:

<!-- key for looking up the wsdl:binding -->
<variable name="binding-key">
  <apply-templates select="." mode="binding-key" />
</variable>

<for-each select="key('binding',$binding-key)">
...
</for-each>

(this also requires some infrastructure code -- the definitions for the keys and the templates; and these definitions are required for each relational structure in the input model, so it is very easy to mess things around resulting in hours of debugging)

Instead of that I was looking for an extension function that will enable me to write something like that:
<for-each select="myxslutils:ref(/wsdl:definitions/wsdl:binding,
  'name', @binding, /wsdl:definitions/@targetNamespace)">
...
</for-each>

      <!-- PROBLEM: works for 'wsdl' prefix,
           for 'tns' and everything else,
           e.g. 'soap', 'xsd', etc., returns null
           -->
      <value-of select="myext:lookupNamespaceUri(current(), 'tns')" />

Note you don't need current() here, although there is no harm in doing
so. The current() function is used to get the context node *outside* an
XPath expression from inside that expression when moving away from the
context node, which you're not doing. So you can just use ".", the dot,
which is the context node (or context item in XSLT 2.0).

    public static String lookupNamespaceUri(final Node currentNode,
            final String prefix) {
        final String namespaceUri;

        namespaceUri =
            currentNode.getOwnerDocument().getDocumentElement()
                .lookupNamespaceURI(prefix);

        return namespaceUri;
    }

I don't know why this doesn't return the expected result. A call to
getNodeName() works just fine.

But then, maybe the expectation is wrong. An XSLT 1.0 processor isn't
obliged to respect your choice of prefixes for namespaces,

Hmmm... It appears that the parser completely ignores all 'xmlns' attributes. The interesting thing is that it reads attributes from other non-null namespaces.

Try to add a breakpoint on http://svn.apache.org/viewvc/xalan/java/trunk/src/org/apache/xml/dtm/ref/DTMNodeProxy.java?view=markup
line #1643

    public String lookupNamespaceURI(String specifiedPrefix) {
    ...
                if (this.hasAttributes()) {
                    NamedNodeMap map = this.getAttributes();
                    int length = map.getLength();
                    for (int i=0;i<length;i++) {
    ...
map.getLength returns 1 as if the 'targetNamespace' was the only attribute. Tried to add
  xmlns:foo="123"
  foo:dummy="abc"
to the wsdl:definitions and now the map.getLength returns 2 and the foo:dummy attribute node node is recognized correctly.


I tested this behavior with the Xerces parser, here is the test class:

package com.acme.apps;

import java.io.File;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import junit.framework.TestCase;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

public class XmlOperationsTest
        extends TestCase {

    private static final String TEST_ROOT_DIR = "target/test-classes";

    private static final String TEST_XML =
        "com/acme/apps/convert-temperature-service.wsdl";

    private static final File TEST_XML_FILE =
        new File(TEST_ROOT_DIR, TEST_XML);

    public final void testLookupNamespaceUri()
            throws ParserConfigurationException, SAXException,
            IOException {
        final DocumentBuilderFactory dbf =
            DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        final DocumentBuilder db = dbf.newDocumentBuilder();
        final Document xml = db.parse(TEST_XML_FILE);
        final Element documentElement = xml.getDocumentElement();

    /* NOTE: stepping inside the implementation of the method below
    reveals that the 'xmlns:' prefixed attributes are counted as the
    rest of attributes, which is different than the Xalan's parser
    behavior. Therefore, I think this is a bug in Xalan. */

        final String tnsUri = documentElement.lookupNamespaceURI("tns");

        System.out.println(tnsUri);

        assertEquals("http://www.webserviceX.NET/";, tnsUri);
    }
}



Reply via email to