Re: Parsing a MODS-document with validation fails

Thomas Scheffler <[email protected]>
Newsgroups gmane.comp.java.jdom.general
Message-ID <[email protected]>
Am 21.07.2011 10:14, schrieb Thomas Scheffler:
> Am 21.07.2011 04:18, schrieb Bradley S. Huffman:
>> Which version of JDOM?  My first guess is it is something in 
>> XMLOutputter.
>
> This is the latest and greatest 1.1.1. I would not suspect 
> XMLOutputter here as it usually does not have any problems with 
> namespaces. This seems to be a parsing issue.

It is a bug in the SAXHandler class where attributes with a different 
Namespace are only detected by their QName and not by the different 
Namespace-URI. I attached a patch that fixes this bug.
It would be great, if this could be integrated and released soon in a 
version 1.1.2.

regards

Thomas Scheffler

>>
>> On Wed, Jul 20, 2011 at 8:23 AM, Thomas Scheffler
>> <[email protected]>  wrote:
>>> Hi,
>>>
>>> if I parse a valid MODS document with XML Schema validation, JDOM 
>>> changes
>>> attributes as it handles default values of schema not correctly (by 
>>> ignoring
>>> the namespace).
>>>
>>> Here is a short code to demonstrate this:
>>>
>>> SAXBuilder builder = new SAXBuilder(true);
>>> builder.setFeature("http://xml.org/sax/features/namespaces", true);
>>> builder.setFeature("http://xml.org/sax/features/namespace-prefixes", 
>>> true);
>>> builder.setFeature("http://apache.org/xml/features/validation/schema",
>>> true);
>>>
>>> Document document = builder.build(new
>>> URL("http://academiccommons.columbia.edu/download/fedora_content/show_pretty/ac:111060/CONTENT/ac111060_description.xml")); 
>>>
>>> XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
>>> xout.output(document, System.out);
>>>
>>> Here is a result fragment:
>>>
>>> <name type="simple">
>>> <namePart type="family">Edwards</namePart>
>>> <namePart type="given">Stephen A.</namePart>
>>> <role>
>>> <roleTerm type="text">author</roleTerm>
>>> </role>
>>> <affiliation>Columbia University. Computer Science</affiliation>
>>> </name>
>>>
>>> If you look at the original document you can see, that @type of name is
>>> "personal". The "simple" comes from the xlink XML-Schema that was 
>>> included
>>> by the MODS-Schema. Therefor the result fragment should look like this:
>>>
>>> <name type="personal" xlink:type="simple">
>>> <namePart type="family">Edwards</namePart>
>>> <namePart type="given">Stephen A.</namePart>
>>> <role>
>>> <roleTerm type="text">author</roleTerm>
>>> </role>
>>> <affiliation>Columbia University. Computer Science</affiliation>
>>> </name>
>>>
>>> If I use DOM from Java this is done correctly (but a bit ugly as it 
>>> does not
>>> use the namespace prefix already defined).
>>>
>>> Could someone just fix this, please?
>
>

_______________________________________________
To control your jdom-interest membership:
http://www.jdom.org/mailman/options/jdom-interest/[email protected]
jdom-namespace.patch (text/x-patch, 3.5 KB)
Index: src/java/org/jdom/input/SAXHandler.java
===================================================================
RCS file: /home/cvspublic/jdom/src/java/org/jdom/input/SAXHandler.java,v
retrieving revision 1.73
diff -u -r1.73 SAXHandler.java
--- src/java/org/jdom/input/SAXHandler.java	10 Nov 2007 05:29:00 -0000	1.73
+++ src/java/org/jdom/input/SAXHandler.java	22 Jul 2011 07:04:29 -0000
@@ -119,6 +119,9 @@
     /** Temporary holder for namespaces that have been declared with
       * startPrefixMapping, but are not yet available on the element */
     private List declaredNamespaces;
+    
+    /** Counter for new namespace prefixes */
+    private int nsPrefixCount;
 
     /** Temporary holder for the internal subset */
     private StringBuffer internalSubset = new StringBuffer();
@@ -141,6 +144,9 @@
     /** The SAX Locator object provided by the parser */
     private Locator locator;
 
+    /** helps to find declared namespaces */
+    private Map nsURIMapping;
+
     /**
      * Class initializer: Populate a table to translate SAX attribute
      * type names into JDOM attribute type value (integer).
@@ -206,6 +212,7 @@
 
         atRoot = true;
         declaredNamespaces = new ArrayList();
+        nsURIMapping = new HashMap();
         externalEntities = new HashMap();
 
         document = this.factory.document(null);
@@ -333,6 +340,7 @@
         if (locator != null) {
             document.setBaseURI(locator.getSystemId());
         }
+        nsPrefixCount=0;
     }
 
     /**
@@ -496,6 +504,7 @@
         if (suppress) return;
 
         Namespace ns = Namespace.getNamespace(prefix, uri);
+        nsURIMapping.put(uri,ns);
         declaredNamespaces.add(ns);
     }
 
@@ -550,6 +559,7 @@
 
             String attLocalName = atts.getLocalName(i);
             String attQName = atts.getQName(i);
+            String attUri=atts.getURI(i);
             int attType = getAttributeType(atts.getType(i));
 
             // Bypass any xmlns attributes which might appear, as we got
@@ -567,10 +577,14 @@
             } else if (!attQName.equals(attLocalName)) {
                 String attPrefix = attQName.substring(0, attQName.indexOf(":"));
                 Namespace attNs = Namespace.getNamespace(attPrefix,
-                                                         atts.getURI(i));
+                                                         attUri);
 
                 attribute = factory.attribute(attLocalName, atts.getValue(i),
                                               attType, attNs);
+            } else if (!"".equals(attUri) && !namespaceURI.equals(attUri)) {
+                Namespace attNs = getUndeclaredNS(attUri);
+                attribute = factory.attribute(attLocalName, atts.getValue(i),
+                        attType, attNs);
             } else {
                 attribute = factory.attribute(attLocalName, atts.getValue(i),
                                               attType);
@@ -589,6 +603,18 @@
         currentElement = element;
     }
 
+    private Namespace getUndeclaredNS(String attUri) {
+        Namespace ns = (Namespace) nsURIMapping.get(attUri);
+        if (ns != null) {
+            return ns;
+        }
+        nsPrefixCount++;
+        ns = Namespace.getNamespace("ns" + nsPrefixCount, attUri);
+        nsURIMapping.put(attUri, ns);
+        declaredNamespaces.add(ns);
+        return ns;
+    }
+
     /**
      * This will take the supplied <code>{@link Element}</code> and
      * transfer its namespaces to the global namespace storage.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.