Re: Parsing a MODS-document with validation fails
Thomas Scheffler <[email protected]>
| Newsgroups | gmane.comp.java.jdom.general |
|---|---|
| Organization | Friedrich-Schiller-Universität Jena |
| Message-ID | <[email protected]> |
Am 25.07.2011 09:05, schrieb Thomas Scheffler: > Am 24.07.2011 23:46, schrieb Bradley S. Huffman: >> And if the prefix "ns1" is already mapped to another URI because the >> user decided to use "ns1" as a prefix, what kind of havoc will this >> cause? > > I got your point! We have to check if "ns"+nsPrefixCount is already > defined, if we create it. I do not know though if that is enough. We can > do this for the current element and be sure of that. But if for instance > we have three tag: "a","b","c", where "a" is parent of "b" an that is > parent of "c". There could be an issue if "a" defines a namespace with > prefix "ns?" that is in use by "c" and not by "b". > When it comes to "b" we see the namespace prefix is currently undefined. > And bound it to the new uri. This way the namespace in c changes. > So we have to drag every usage of a prefix throughout the document with > the "endPrefixMapping" event, that is currently missing an > implementation in SAXHandler. > Do you agree? I prepared a new version of the patch that uses the "endPrefixMapping" event to handle namespace prefixes and also checks if "ns"+nsPrefixCount is already defined. regards, Thomas >> >> On Fri, Jul 22, 2011 at 4:08 PM, Thomas Scheffler >> <[email protected]> wrote: >>> Am 22.07.2011 22:53, schrieb Bradley S. Huffman: >>>> >>>> I'm not sure about a patch that makes up a namespace prefix. From the >>>> patch >>>> >>>> nsPrefixCount++; >>>> ns = Namespace.getNamespace("ns" + nsPrefixCount, attUri); >>>> >>>> >>>> Seems like a kludge. My gut says it's something else. >>> >>> This is how it is done by the Oracle JAVA DocumentBuilder. JDOM won't >>> accept >>> a namespace without a prefix so you have to build some as the SAXParser >>> delivers an attribute with QName=LocalName. Before that I take a look in >>> predeclared namespaces, so that any prefix that is bound to an URI is >>> used >>> before building a new one. For the testing case I submitted in my >>> original >>> mail, "xlink" is found correctly which makes it more beautiful than the >>> DocumentBuilder solution that creates "ns0" on every element with >>> xlink:type >>> set fixed to "simple". Hope you can follow my arguments. _______________________________________________ To control your jdom-interest membership: http://www.jdom.org/mailman/options/jdom-interest/[email protected]
jdom-namespace.patch
(text/x-patch, 6.3 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 25 Jul 2011 09:13:48 -0000
@@ -83,6 +83,9 @@
/** Hash table to map SAX attribute type names to JDOM attribute types. */
private static final Map attrNameToTypeMap = new HashMap(13);
+ /** If namespace prefix is undeclared use this a a prefix for nsPrefixCount */
+ private static final String UNDECLARED_NS_PREFIX = "ns";
+
/** <code>Document</code> object being built */
private Document document;
@@ -120,6 +123,16 @@
* startPrefixMapping, but are not yet available on the element */
private List declaredNamespaces;
+ /** Temporary holder for namespaces that have not been declared with
+ * startPrefixMapping, but are required due to schema rules */
+ private List undeclaredNamespaces;
+
+ /** Holds information of namespace the a currently available in the current context. */
+ private HashMap usedNamespaces;
+
+ /** Counter for new namespace prefixes */
+ private int nsPrefixCount;
+
/** Temporary holder for the internal subset */
private StringBuffer internalSubset = new StringBuffer();
@@ -141,6 +154,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 +222,9 @@
atRoot = true;
declaredNamespaces = new ArrayList();
+ undeclaredNamespaces = new ArrayList();
+ usedNamespaces = new HashMap();
+ nsURIMapping = new HashMap();
externalEntities = new HashMap();
document = this.factory.document(null);
@@ -333,6 +352,7 @@
if (locator != null) {
document.setBaseURI(locator.getSystemId());
}
+ nsPrefixCount=0;
}
/**
@@ -496,7 +516,15 @@
if (suppress) return;
Namespace ns = Namespace.getNamespace(prefix, uri);
- declaredNamespaces.add(ns);
+
+ nsURIMapping.put(uri,ns); //removed in endPrefixMapping()
+ List namespaces = (List) usedNamespaces.get(prefix);
+ if (namespaces == null) {
+ namespaces = new ArrayList();
+ usedNamespaces.put(prefix, namespaces);
+ }
+ namespaces.add(ns); //removed in endPrefixMapping()
+ declaredNamespaces.add(ns); //removed in transferNamespaces()
}
/**
@@ -550,6 +578,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 +596,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 +622,32 @@
currentElement = element;
}
+ private Namespace getUndeclaredNS(String attUri) {
+ Namespace ns = (Namespace) nsURIMapping.get(attUri);
+ if (ns != null) {
+ return ns;
+ }
+ ns = createNamespaceWithPrefix(attUri);
+ return ns;
+ }
+
+ /**
+ * @param attUri
+ * @return
+ */
+ private Namespace createNamespaceWithPrefix(String attUri) {
+ Namespace ns = null;
+ boolean inUse=true;
+ while (inUse){
+ String prefix = UNDECLARED_NS_PREFIX + nsPrefixCount++;
+ ns = Namespace.getNamespace(prefix, attUri);
+ inUse = usedNamespaces.containsKey(prefix);
+ }
+ nsURIMapping.put(attUri, ns);
+ undeclaredNamespaces.add(ns);
+ return ns;
+ }
+
/**
* This will take the supplied <code>{@link Element}</code> and
* transfer its namespaces to the global namespace storage.
@@ -604,6 +663,15 @@
}
}
declaredNamespaces.clear();
+ i = undeclaredNamespaces.iterator();
+ while (i.hasNext()) {
+ Namespace ns = (Namespace)i.next();
+ if (ns != element.getNamespace()) {
+ element.addNamespaceDeclaration(ns);
+ }
+ nsURIMapping.remove(ns.getURI());
+ }
+ undeclaredNamespaces.clear();
}
/**
@@ -732,6 +800,23 @@
}
/**
+ * Receive notification of the end of a Namespace mapping.
+ *
+ * Will remove any information on prefix of that namespace.
+ *
+ * @param prefix The Namespace prefix being declared.
+ * @exception org.xml.sax.SAXException Any SAX exception, possibly
+ * wrapping another exception.
+ * @see org.xml.sax.ContentHandler#endPrefixMapping
+ */
+ public void endPrefixMapping(String prefix) throws SAXException {
+ List namespaces=(List) usedNamespaces.get(prefix);
+ int index = namespaces.size()-1;
+ Namespace ns = (Namespace) namespaces.remove(index);
+ nsURIMapping.values().remove(ns);
+ }
+
+ /**
* This will signify that a DTD is being parsed, and can be
* used to ensure that comments and other lexical structures
* in the DTD are not added to the JDOM <code>Document</code>