FOP-3127: Allow XMP at PDF page level
diff --git a/src/main/java/org/apache/xmlgraphics/xmp/Metadata.java b/src/main/java/org/apache/xmlgraphics/xmp/Metadata.java
index d1feb75..5f8a44e 100644
--- a/src/main/java/org/apache/xmlgraphics/xmp/Metadata.java
+++ b/src/main/java/org/apache/xmlgraphics/xmp/Metadata.java
@@ -39,7 +39,7 @@
*/
public class Metadata implements XMLizable, PropertyAccess {
- private Map properties = new java.util.HashMap();
+ private Map<QName, XMPProperty> properties = new java.util.HashMap<>();
/** {@inheritDoc} */
public void setProperty(XMPProperty prop) {
@@ -53,13 +53,12 @@
/** {@inheritDoc} */
public XMPProperty getProperty(QName name) {
- XMPProperty prop = (XMPProperty)properties.get(name);
- return prop;
+ return properties.get(name);
}
/** {@inheritDoc} */
public XMPProperty removeProperty(QName name) {
- return (XMPProperty)properties.remove(name);
+ return properties.remove(name);
}
/** {@inheritDoc} */
@@ -102,6 +101,9 @@
handler.startElement(XMPConstants.XMP_NAMESPACE, "xmpmeta", "x:xmpmeta", atts);
handler.startPrefixMapping("rdf", XMPConstants.RDF_NAMESPACE);
handler.startElement(XMPConstants.RDF_NAMESPACE, "RDF", "rdf:RDF", atts);
+
+ writeCustomDescription(handler);
+
//Get all property namespaces
Set namespaces = new java.util.HashSet();
Iterator iter = properties.keySet().iterator();
@@ -121,7 +123,7 @@
for (Object o : properties.values()) {
XMPProperty prop = (XMPProperty) o;
- if (prop.getName().getNamespaceURI().equals(ns)) {
+ if (prop.getName().getNamespaceURI().equals(ns) && !prop.attribute) {
if (first) {
if (prefix == null) {
prefix = prop.getName().getPrefix();
@@ -154,4 +156,27 @@
handler.endPrefixMapping("x");
}
+ private void writeCustomDescription(ContentHandler handler) throws SAXException {
+ AttributesImpl atts = new AttributesImpl();
+ boolean empty = true;
+ for (XMPProperty prop : properties.values()) {
+ if (prop.attribute) {
+ atts.addAttribute(prop.getNamespace(), prop.getName().getLocalName(), prop.getName().getQName(),
+ "CDATA", (String) prop.getValue());
+ if (prop.getName().getPrefix() != null) {
+ handler.startPrefixMapping(prop.getName().getPrefix(), prop.getNamespace());
+ handler.endPrefixMapping(prop.getName().getPrefix());
+ }
+ empty = false;
+ }
+ }
+ if (!empty) {
+ atts.addAttribute(XMPConstants.RDF_NAMESPACE,
+ "about", "rdf:about", "CDATA", "");
+ handler.startElement(XMPConstants.RDF_NAMESPACE,
+ "RDF", "rdf:Description", atts);
+ handler.endElement(XMPConstants.RDF_NAMESPACE, "RDF", "rdf:Description");
+ }
+ }
+
}
diff --git a/src/main/java/org/apache/xmlgraphics/xmp/XMPArray.java b/src/main/java/org/apache/xmlgraphics/xmp/XMPArray.java
index 018768c..da79790 100644
--- a/src/main/java/org/apache/xmlgraphics/xmp/XMPArray.java
+++ b/src/main/java/org/apache/xmlgraphics/xmp/XMPArray.java
@@ -21,6 +21,7 @@
import java.net.URI;
+import java.util.ArrayList;
import java.util.List;
import org.xml.sax.ContentHandler;
@@ -36,6 +37,7 @@
private XMPArrayType type;
private List values = new java.util.ArrayList();
private List xmllang = new java.util.ArrayList();
+ private List<String> parseTypes = new ArrayList<>();
/**
* Main constructor
@@ -151,9 +153,23 @@
* Adds a new value to the array
* @param value the value
*/
- public void add(Object value) {
+ public void add(Object value, String lang, String parseType) {
values.add(value);
- xmllang.add(null);
+ xmllang.add(lang);
+ parseTypes.add(parseType);
+ }
+
+ /**
+ * Adds a language-dependent value to the array. Make sure not to add the same language twice.
+ * @param value the value
+ * @param lang the language ("x-default" for the default value)
+ */
+ public void add(Object value, String lang) {
+ add(value, lang, null);
+ }
+
+ public void add(Object value) {
+ add(value, null, null);
}
/**
@@ -166,6 +182,7 @@
if (idx >= 0) {
values.remove(idx);
xmllang.remove(idx);
+ parseTypes.remove(idx);
return true;
}
return false;
@@ -173,16 +190,6 @@
}
/**
- * Adds a language-dependent value to the array. Make sure not to add the same language twice.
- * @param value the value
- * @param lang the language ("x-default" for the default value)
- */
- public void add(String value, String lang) {
- values.add(value);
- xmllang.add(lang);
- }
-
- /**
* Returns the current number of values in the array.
* @return the current number of values in the array
*/
@@ -226,6 +233,10 @@
atts.addAttribute(XMPConstants.RDF_NAMESPACE, "resource",
"rdf:resource", "CDATA", ((URI)v).toString());
}
+ String parseType = parseTypes.get(i);
+ if (parseType != null) {
+ atts.addAttribute(XMPConstants.RDF_NAMESPACE, "parseType", "rdf:parseType", "CDATA", parseType);
+ }
handler.startElement(XMPConstants.RDF_NAMESPACE,
"li", "rdf:li", atts);
if (v instanceof XMPComplexValue) {
diff --git a/src/main/java/org/apache/xmlgraphics/xmp/XMPHandler.java b/src/main/java/org/apache/xmlgraphics/xmp/XMPHandler.java
index b3b918f..2eed5df 100644
--- a/src/main/java/org/apache/xmlgraphics/xmp/XMPHandler.java
+++ b/src/main/java/org/apache/xmlgraphics/xmp/XMPHandler.java
@@ -153,6 +153,7 @@
String qn = attributes.getQName(i);
String v = attributes.getValue(i);
XMPProperty prop = new XMPProperty(new QName(ns, qn), v);
+ prop.attribute = true;
getCurrentProperties().setProperty(prop);
}
}
@@ -204,6 +205,12 @@
this.nestingInfoStack.push("struct");
}
+ private void startThinStructure() {
+ XMPThinStructure struct = new XMPThinStructure();
+ contextStack.push(struct);
+ nestingInfoStack.push("struct");
+ }
+
/** {@inheritDoc} */
public void endElement(String uri, String localName, String qName) throws SAXException {
Attributes atts = (Attributes)attributesStack.pop();
@@ -212,27 +219,24 @@
} else if (XMPConstants.RDF_NAMESPACE.equals(uri) && !"value".equals(localName)) {
if ("li".equals(localName)) {
XMPStructure struct = getCurrentStructure();
+ String parseType = atts.getValue("rdf:parseType");
if (struct != null) {
//Pop the structure
this.contextStack.pop();
this.nestingInfoStack.pop();
- getCurrentArray(true).add(struct);
+ getCurrentArray(true).add(struct, null, parseType);
} else {
String s = content.toString().trim();
if (s.length() > 0) {
String lang = atts.getValue(XMPConstants.XML_NS, "lang");
- if (lang != null) {
- getCurrentArray(true).add(s, lang);
- } else {
- getCurrentArray(true).add(s);
- }
+ getCurrentArray(true).add(s, lang, parseType);
} else {
String res = atts.getValue(XMPConstants.RDF_NAMESPACE,
"resource");
if (res != null) {
try {
URI resource = new URI(res);
- getCurrentArray(true).add(resource);
+ getCurrentArray(true).add(resource, null, parseType);
} catch (URISyntaxException e) {
throw new SAXException("rdf:resource value is not a well-formed URI", e);
}
@@ -288,7 +292,7 @@
throw new IllegalStateException("No content in XMP property");
}
if (getCurrentProperties() == null) {
- startStructure();
+ startThinStructure();
}
getCurrentProperties().setProperty(prop);
}
diff --git a/src/main/java/org/apache/xmlgraphics/xmp/XMPProperty.java b/src/main/java/org/apache/xmlgraphics/xmp/XMPProperty.java
index 5f2b5ed..d7718d6 100644
--- a/src/main/java/org/apache/xmlgraphics/xmp/XMPProperty.java
+++ b/src/main/java/org/apache/xmlgraphics/xmp/XMPProperty.java
@@ -40,6 +40,7 @@
private Object value;
private String xmllang;
private Map qualifiers;
+ protected boolean attribute;
/**
* Creates a new XMP property.
@@ -186,6 +187,9 @@
String prefix = getName().getPrefix();
if (prefix == null || "".equals(prefix)) {
XMPSchema schema = XMPSchemaRegistry.getInstance().getSchema(getNamespace());
+ if (schema == null) {
+ return getName().getLocalName();
+ }
prefix = schema.getPreferredPrefix();
}
return prefix + ":" + getName().getLocalName();
diff --git a/src/main/java/org/apache/xmlgraphics/xmp/XMPStructure.java b/src/main/java/org/apache/xmlgraphics/xmp/XMPStructure.java
index 86f3d20..ba7bcd8 100644
--- a/src/main/java/org/apache/xmlgraphics/xmp/XMPStructure.java
+++ b/src/main/java/org/apache/xmlgraphics/xmp/XMPStructure.java
@@ -33,7 +33,7 @@
*/
public class XMPStructure extends XMPComplexValue implements PropertyAccess {
- private Map properties = new java.util.HashMap();
+ protected Map properties = new java.util.HashMap();
/**
* Main constructor
diff --git a/src/main/java/org/apache/xmlgraphics/xmp/XMPThinStructure.java b/src/main/java/org/apache/xmlgraphics/xmp/XMPThinStructure.java
new file mode 100644
index 0000000..afc015f
--- /dev/null
+++ b/src/main/java/org/apache/xmlgraphics/xmp/XMPThinStructure.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+package org.apache.xmlgraphics.xmp;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+public class XMPThinStructure extends XMPStructure {
+ public void toSAX(ContentHandler handler) throws SAXException {
+ for (Object o : properties.values()) {
+ XMPProperty prop = (XMPProperty) o;
+ prop.toSAX(handler);
+ }
+ }
+}
diff --git a/src/test/java/org/apache/xmlgraphics/xmp/XMPParserTestCase.java b/src/test/java/org/apache/xmlgraphics/xmp/XMPParserTestCase.java
index 76ecd81..922f148 100644
--- a/src/test/java/org/apache/xmlgraphics/xmp/XMPParserTestCase.java
+++ b/src/test/java/org/apache/xmlgraphics/xmp/XMPParserTestCase.java
@@ -33,6 +33,9 @@
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.DefaultHandler;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -204,21 +207,44 @@
final StringBuilder sb = new StringBuilder();
meta.toSAX(new DefaultHandler() {
public void startElement(String uri, String localName, String qName, Attributes attributes) {
- sb.append(qName).append("\n");
+ sb.append("<").append(qName);
+ for (int i = 0; i < attributes.getLength(); i++) {
+ sb.append(" ").append(attributes.getQName(i)).append("=").append(attributes.getValue(i));
+ }
+ sb.append(">\n");
}
});
- assertEquals("x:xmpmeta\n"
- + "rdf:RDF\n"
- + "rdf:Description\n"
- + "pdfaExtension:schemas\n"
- + "rdf:Bag\n"
- + "rdf:li\n"
- + "rdf:Description\n"
- + "pdfaSchema:property\n"
- + "rdf:Seq\n"
- + "rdf:li\n"
- + "rdf:Description\n"
- + "pdfaProperty:name\n", sb.toString());
+ assertEquals("<x:xmpmeta>\n"
+ + "<rdf:RDF>\n"
+ + "<rdf:Description abc:xyz=rty rdf:about=>\n"
+ + "<rdf:Description rdf:about=>\n"
+ + "<pdfaExtension:schemas>\n"
+ + "<rdf:Bag>\n"
+ + "<rdf:li rdf:parseType=Resource>\n"
+ + "<pdfaSchema:property>\n"
+ + "<rdf:Seq>\n"
+ + "<rdf:li rdf:parseType=Resource>\n"
+ + "<pdfaProperty:name>\n", sb.toString());
+ }
+
+ @Test
+ public void testNoNamespace() throws Exception {
+ URL url = getClass().getResource("test-no-namespace.xmp");
+ Metadata meta = XMPParser.parseXMP(url);
+ final StringBuilder sb = new StringBuilder();
+ meta.toSAX(new DefaultHandler() {
+ public void startElement(String uri, String localName, String qName, Attributes attributes) {
+ sb.append("<").append(qName);
+ for (int i = 0; i < attributes.getLength(); i++) {
+ sb.append(" ").append(attributes.getQName(i)).append("=").append(attributes.getValue(i));
+ }
+ sb.append(">\n");
+ }
+ });
+ assertEquals("<x:xmpmeta>\n"
+ + "<rdf:RDF>\n"
+ + "<rdf:Description rdf:about=>\n"
+ + "<a>\n", sb.toString());
}
@Test
diff --git a/src/test/java/org/apache/xmlgraphics/xmp/test-no-namespace.xmp b/src/test/java/org/apache/xmlgraphics/xmp/test-no-namespace.xmp
new file mode 100644
index 0000000..30819a8
--- /dev/null
+++ b/src/test/java/org/apache/xmlgraphics/xmp/test-no-namespace.xmp
@@ -0,0 +1,3 @@
+<x:xmpmeta xmlns:x="adobe:ns:meta/">
+<a/>
+</x:xmpmeta>
\ No newline at end of file
diff --git a/src/test/java/org/apache/xmlgraphics/xmp/test-subproperty.xmp b/src/test/java/org/apache/xmlgraphics/xmp/test-subproperty.xmp
index 2384f54..492de77 100644
--- a/src/test/java/org/apache/xmlgraphics/xmp/test-subproperty.xmp
+++ b/src/test/java/org/apache/xmlgraphics/xmp/test-subproperty.xmp
@@ -1,5 +1,6 @@
<x:xmpmeta xmlns:x="adobe:ns:meta/">
- <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:abc="http://www.abc.de/abc/">
+ <rdf:Description rdf:about="" abc:xyz="rty"/>
<rdf:Description xmlns:pdfaExtension="http://www.aiim.org/pdfa/ns/extension/"
xmlns:pdfaSchema="http://www.aiim.org/pdfa/ns/schema#"
xmlns:pdfaProperty="http://www.aiim.org/pdfa/ns/property#" rdf:about="">