I have some questions about the processing in BaseStAXArtifactProcessor to
write namespace prefixes.  Let's start with this method:

    protected void writeStart(XMLStreamWriter writer, String uri, String
name, XAttr... attrs) throws XMLStreamException {
        String prefix = writeElementPrefix(writer, uri);
        writeAttributePrefixes(writer, attrs);
        writer.writeStartElement(uri, name);

        if (prefix != null){
            writer.writeNamespace(prefix,uri);
        }
        writeAttributes(writer, attrs);
    }

writeAttributePrefixes calls down to XAttr.writePrefix.  If the value is a
QName then it calls writeQNamePrefix.

        private void writeQNamePrefix(XMLStreamWriter writer, QName qname)
throws XMLStreamException {
            if (qname != null) {
                String prefix = qname.getPrefix();
                String uri = qname.getNamespaceURI();
                prefix = writer.getPrefix(uri);
                if (prefix != null) {
                    return;
                } else {

                    // Find an available prefix and bind it to the given URI

                    NamespaceContext nsc = writer.getNamespaceContext();
                    for (int i=1; ; i++) {
                        prefix = "ns" + i;
                        if (nsc.getNamespaceURI(prefix) == null) {
                            break;
                        }
                    }
                    writer.setPrefix(prefix, uri);
                }
            }
        }

If the QName has a uri which isn't yet bound to a prefix, this method binds
it.  Note that it does not write the namespace to the stream, nor does it
return anything to its caller to tell it to write the namespace.  So the
resulting XML has an unbound prefix.  writeQNamePrefix cannot write the
namespace itself because it is being called before the element has been
started.  I think the processing needs to be changed to bubble up the prefix
bindings back to writeStart, and then writeStart can write them.

PolicyAttachPointProcessor.writePolicyPrefixes also goes through this code,
so it would also have to be changed to return the prefix bindings to its
callers (ConfiguredOperationProcessor, JavaImplementationProcessor).

I gather that the reason the code is arranged this way is to minimize the
number of prefixes generated by binding the prefix in the parent's element
rather than the element we are about to write?  Otherwise writeQNameValue
could just write the namespace at the time the attribute value is being
written.

Speaking of writeQName value, I have a question about it too.

        private String writeQNameValue(XMLStreamWriter writer, QName qname)
throws XMLStreamException {
            if (qname != null) {
                String prefix = qname.getPrefix();
                String uri = qname.getNamespaceURI();
                prefix = writer.getPrefix(uri);
                if (prefix != null && prefix.length() > 0) {

                    // Use the prefix already bound to the given URI
                    return prefix + ":" + qname.getLocalPart();
                } else {

                    // Find an available prefix and bind it to the given URI

                    NamespaceContext nsc = writer.getNamespaceContext();
                    for (int i=1; ; i++) {
                        prefix = "ns" + i;
                        if (nsc.getNamespaceURI(prefix) == null) {
                            break;
                        }
                    }
                    writer.setPrefix(prefix, uri);
                    writer.writeNamespace(prefix, uri);
                    return prefix + ":" + qname.getLocalPart();
                }
            } else {
                return null;
            }
        }

I am wondering about the check for prefix.length() > 0.  The documentation
for getPrefix() is sketchy, but it seems to return the empty string if the
given namespace is the default namespace.  So this code generates a new
prefix when the QName value uses the default namespace.  Why does it do
that?  I think if getPrefix returns a non-null value of zero length, this
method should return the local part of the QName with no prefix.

Greg Dritschler

Reply via email to