[ 
https://issues.apache.org/jira/browse/TUSCANY-2342?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Jean-Sebastien Delfino resolved TUSCANY-2342.
---------------------------------------------

    Resolution: Fixed

I looked into this and observed the following:

1. the code was designed to work with XMLOutputFactory.IS_REPAIRING_NAMESPACES 
= true, making the XMLOutputFactory responsible for writing the namespace 
prefix declarations for the namespaces in context and making sure that one 
prefix is declared per namespace used in elements and attributes.

2. since we were not writing the namespaces ourselves we didn't have a problem 
with namespace prefix declarations being written in the parent element (since 
the XMLOutputFactory was generating them in the correct element context)

3. we had to handle the writing of namespace declarations ourselves when 
writing QName attribute values as IS_REPAIRING_NAMESPACES does not cover that 
case (it only handles namespaces in element and attribute names)

4. in that code we used to generate an unnecessary namespace prefix for the 
default namespace (as we did not recognize that prefix == "" was referring to 
the default namespace), this was a non-breaking bug.

I fixed (4).

I also changed the code a little to call XAttr.setPrefix after 
writeStartElement() and explicitly call writeNamespace() for namespaces in 
attribute names.

This should have not have a visible effect with an XMLOutputFactory configured 
with IS_REPAIRING_NAMESPACES = true, but should now generate namespace prefix 
declarations with an XMLOutputFactory not using that option.

I recommend using IS_REPAIRING_NAMESPACES anyway as it handles duplicate 
namespace prefix declarations better, and is also the option we set by default 
in the Tuscany runtime.


> Problems in BaseStAXArtifactProcessor with writing prefixes
> -----------------------------------------------------------
>
>                 Key: TUSCANY-2342
>                 URL: https://issues.apache.org/jira/browse/TUSCANY-2342
>             Project: Tuscany
>          Issue Type: Bug
>          Components: Java SCA Assembly Model
>            Reporter: Greg Dritschler
>            Assignee: Jean-Sebastien Delfino
>
> I think that BaseStAXArtifactProcessor has some bugs related to writing 
> namespace prefixes for attribute values.
> 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 XAttr.writePrefix calls XAttr.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 which will cause problems for anyone 
> re-reading the composite.
> writeQNamePrefix cannot write the namespace itself because it is being called 
> by writeStart before the element has been started.  If this is the root 
> element of the document, attempting to do a write at this point will cause an 
> exception.
> I'm not sure why the code is arranged this way.  I thought it might be 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.  But that 
> doesn't work when you are working with the root element and don't have a 
> parent element.
> So I don't know why this structure of separately writing the prefixes is 
> here.  XAttr.writeQNameValue has code to bind a prefix to a new URI, and it 
> DOES write the prefix-uri binding to the stream.  Why isn't that good enough?
> Speaking of writeQNameValue, 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.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to