Author: tilman
Date: Thu Nov 27 15:29:17 2025
New Revision: 1930033
Log:
PDFBOX-2378: add namespace declaration of simple properties to rdf element to
avoid them getting lost in serialization
Modified:
pdfbox/trunk/xmpbox/src/main/java/org/apache/xmpbox/xml/XmpSerializer.java
pdfbox/trunk/xmpbox/src/test/java/org/apache/xmpbox/parser/DeserializationTest.java
Modified:
pdfbox/trunk/xmpbox/src/main/java/org/apache/xmpbox/xml/XmpSerializer.java
==============================================================================
--- pdfbox/trunk/xmpbox/src/main/java/org/apache/xmpbox/xml/XmpSerializer.java
Thu Nov 27 15:29:13 2025 (r1930032)
+++ pdfbox/trunk/xmpbox/src/main/java/org/apache/xmpbox/xml/XmpSerializer.java
Thu Nov 27 15:29:17 2025 (r1930033)
@@ -56,6 +56,7 @@ public class XmpSerializer
private final TransformerFactory transformerFactory;
private final DocumentBuilder documentBuilder;
+ private Element rdf;
/**
* Default constructor.
@@ -92,7 +93,7 @@ public class XmpSerializer
{
Document doc = documentBuilder.newDocument();
// fill document
- Element rdf = createRdfElement(doc, metadata, withXpacket);
+ rdf = createRdfElement(doc, metadata, withXpacket);
for (XMPSchema schema : metadata.getAllSchemas())
{
rdf.appendChild(serializeSchema(doc, schema));
@@ -164,6 +165,13 @@ public class XmpSerializer
attribute.getValue());
}
}
+
+ // PDFBOX-2378 part 2: add namespace declaration to the top
+ if (!field.getPrefix().isEmpty() && field.getNamespace() !=
null && !field.getNamespace().isEmpty())
+ {
+ rdf.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
"xmlns:" + field.getPrefix(), field.getNamespace());
+ }
+
parent.appendChild(esimple);
}
else if (field instanceof ArrayProperty)
@@ -289,11 +297,11 @@ public class XmpSerializer
doc.appendChild(endXPacket);
}
// rdf element
- Element rdf = doc.createElementNS(XmpConstants.RDF_NAMESPACE,
"rdf:RDF");
+ Element rdfElement = doc.createElementNS(XmpConstants.RDF_NAMESPACE,
"rdf:RDF");
// rdf.setAttributeNS(XMPSchema.NS_NAMESPACE, qualifiedName, value)
- xmpmeta.appendChild(rdf);
+ xmpmeta.appendChild(rdfElement);
// return the rdf element where all will be put
- return rdf;
+ return rdfElement;
}
/**
@@ -321,4 +329,4 @@ public class XmpSerializer
// save
transformer.transform(source, result);
}
-}
+}
\ No newline at end of file
Modified:
pdfbox/trunk/xmpbox/src/test/java/org/apache/xmpbox/parser/DeserializationTest.java
==============================================================================
---
pdfbox/trunk/xmpbox/src/test/java/org/apache/xmpbox/parser/DeserializationTest.java
Thu Nov 27 15:29:13 2025 (r1930032)
+++
pdfbox/trunk/xmpbox/src/test/java/org/apache/xmpbox/parser/DeserializationTest.java
Thu Nov 27 15:29:17 2025 (r1930033)
@@ -89,10 +89,11 @@ class DeserializationTest
@Test
void testStructuredRecursive() throws XmpParsingException,
TransformerException, NoSuchAlgorithmException, IOException
{
+ // not valid XMP according to
https://www.pdflib.com/pdf-knowledge-base/xmp/free-xmp-validator/
try (InputStream is =
DomXmpParser.class.getResourceAsStream("/org/apache/xmpbox/parser/structured_recursive.xml"))
{
XMPMetadata metadata = xdb.parse(is);
- checkTransform(metadata,
"50429052370059903229869639943824137435756655804864824611365505219590816799783");
+ checkTransform(metadata,
"52753264982056308826419701767667619100664406974698584945629426171445624909200",
metadata.getAllSchemas().size());
}
}
@@ -102,7 +103,7 @@ class DeserializationTest
try (InputStream is =
DomXmpParser.class.getResourceAsStream("/org/apache/xmpbox/parser/empty_list.xml"))
{
XMPMetadata metadata = xdb.parse(is);
- checkTransform(metadata,
"92757984740574362800045336947395134346147179161385043989715484359442690118913");
+ checkTransform(metadata,
"19567447256605061134904612869562878052777123273535814661244629430271579345577",
metadata.getAllSchemas().size());
}
}
@@ -114,7 +115,7 @@ class DeserializationTest
XMPMetadata metadata = xdb.parse(is);
DublinCoreSchema dc = metadata.getDublinCoreSchema();
dc.getCreatorsProperty();
- checkTransform(metadata,
"84846877440303452108560435796840772468446174326989274262473618453524301429629");
+ checkTransform(metadata,
"39450703080437563739186076111811684356424147071014681699119272065568305393521",
metadata.getAllSchemas().size());
}
}
@@ -136,7 +137,7 @@ class DeserializationTest
try (InputStream is =
DomXmpParser.class.getResourceAsStream("/org/apache/xmpbox/parser/AltBagSeqTest.xml"))
{
XMPMetadata metadata = xdb.parse(is);
- checkTransform(metadata,
"16805992283807186369849610414335227396239089071611806706387795179375897398118");
+ checkTransform(metadata,
"19154431745733679891721944365143324348437445906324353036103478292448653362772",
metadata.getAllSchemas().size());
}
}
@@ -179,7 +180,7 @@ class DeserializationTest
assertEquals("JPEG", thumb.getFormat());
assertEquals("/9j/4AAQSkZJRgABAgEASABIAAD", thumb.getImage());
- checkTransform(metadata,
"29120813843205587378639665706339183422557956085575883885304382528664692315203");
+ checkTransform(metadata,
"84558386150683037967795120526515137256954964034058806864845109667021390825020",
metadata.getAllSchemas().size());
}
}
@@ -343,7 +344,7 @@ class DeserializationTest
XMPBasicSchema basic = metadata.getXMPBasicSchema();
assertNotNull(basic.getCreateDate());
- checkTransform(metadata,
"18065297971979344549773207273794555094175502580946345976611821901439849242965");
+ checkTransform(metadata,
"103011318952861241491609772230618389876889507758821590919505444434501582047075",
metadata.getAllSchemas().size());
}
}
@@ -360,12 +361,12 @@ class DeserializationTest
// check creator tool
assertEquals("Canon ",
metadata.getXMPBasicSchema().getCreatorTool());
- checkTransform(metadata,
"65475542891943378255730260794798768587695617138297196920293698476028940113080");
+ checkTransform(metadata,
"35040104785033687813052387728441520994588808120158942942660631178163542677230",
metadata.getAllSchemas().size());
}
}
@Test
- void testMetadataParsing() throws TransformerException,
NoSuchAlgorithmException
+ void testMetadataParsing() throws TransformerException,
NoSuchAlgorithmException, XmpParsingException
{
XMPMetadata metadata = XMPMetadata.createXMPMetadata();
@@ -379,7 +380,7 @@ class DeserializationTest
pdf.setProducer("Producer");
pdf.setPDFVersion("1.4");
- checkTransform(metadata,
"90022311886271402508155234494196354960301469636090129252744270615851988530557");
+ checkTransform(metadata,
"24727341753942351260821151680330022244742411666459385225917195999704816908515",
metadata.getAllSchemas().size());
}
/**
@@ -401,12 +402,12 @@ class DeserializationTest
+ " </rdf:RDF>\n"
+ "</x:xmpmeta>\n"
+ "<?xpacket end=\"w\"?>";
- XMPMetadata xmp = xdb.parse(xmpmeta.getBytes(StandardCharsets.UTF_8));
- checkTransform(xmp,
"8175296932768628269367133054275876764131784758539061072921527253098102430315");
+ XMPMetadata metadata =
xdb.parse(xmpmeta.getBytes(StandardCharsets.UTF_8));
+ checkTransform(metadata,
"114563613226112098345006389295317658957506710850378716324758103164733276333281",
metadata.getAllSchemas().size());
}
- private void checkTransform(XMPMetadata metadata, String expected)
- throws TransformerException, NoSuchAlgorithmException
+ private void checkTransform(XMPMetadata metadata, String expected, int
expectedSchemaCount)
+ throws TransformerException, NoSuchAlgorithmException,
XmpParsingException
{
serializer.serialize(metadata, baos, true);
String replaced =
baos.toString(StandardCharsets.UTF_8).replace("\r\n", "\n");
@@ -414,5 +415,7 @@ class DeserializationTest
byte[] digest = MessageDigest.getInstance("SHA-256").digest(ba);
String result = new BigInteger(1, digest).toString();
assertEquals(expected, result, "output:\n" + replaced);
+ XMPMetadata xmp = xdb.parse(baos.toByteArray()); // tests round trip
+ assertEquals(expectedSchemaCount, xmp.getAllSchemas().size());
}
}