diff --git a/README.md b/README.md
index 3f1e0854..d5de02f6 100644
--- a/README.md
+++ b/README.md
@@ -302,6 +302,8 @@ They depend on several other libraries so I suggest you are going for the Maven
# News and noteworthy
+* v9.6.2 - work in progress
+ * Reworked the Peppol Document Type Identifier data model to handle non-XML syntax specific IDs as well
* v9.6.1 - 2024-12-16
* Added new class `PeppolNaptrURLProvider`
* Fixed the Peppol Directory URL of `EPeppolNetwork.PRODUCTION`
diff --git a/peppol-id/src/main/java/com/helger/peppolid/peppol/doctype/IPeppolDocumentTypeIdentifierParts.java b/peppol-id/src/main/java/com/helger/peppolid/peppol/doctype/IPeppolDocumentTypeIdentifierParts.java
index 4d62eb30..82aeee60 100644
--- a/peppol-id/src/main/java/com/helger/peppolid/peppol/doctype/IPeppolDocumentTypeIdentifierParts.java
+++ b/peppol-id/src/main/java/com/helger/peppolid/peppol/doctype/IPeppolDocumentTypeIdentifierParts.java
@@ -29,7 +29,7 @@
public interface IPeppolDocumentTypeIdentifierParts extends IPeppolGenericDocumentTypeIdentifierParts
{
/**
- * Separator between namespace URI and local name
+ * Separator between XML root element namespace URI and local name
*/
String NAMESPACE_SEPARATOR = "::";
diff --git a/peppol-id/src/main/java/com/helger/peppolid/peppol/doctype/PeppolDocumentTypeIdentifierParts.java b/peppol-id/src/main/java/com/helger/peppolid/peppol/doctype/PeppolDocumentTypeIdentifierParts.java
index 352a77ae..65720303 100644
--- a/peppol-id/src/main/java/com/helger/peppolid/peppol/doctype/PeppolDocumentTypeIdentifierParts.java
+++ b/peppol-id/src/main/java/com/helger/peppolid/peppol/doctype/PeppolDocumentTypeIdentifierParts.java
@@ -16,7 +16,10 @@
*/
package com.helger.peppolid.peppol.doctype;
+import java.util.function.BiConsumer;
+
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import com.helger.commons.ValueEnforcer;
@@ -24,6 +27,7 @@
import com.helger.commons.collection.impl.ICommonsList;
import com.helger.commons.string.StringHelper;
import com.helger.commons.string.ToStringGenerator;
+import com.helger.commons.wrapper.Wrapper;
import com.helger.peppolid.IDocumentTypeIdentifier;
/**
@@ -39,6 +43,20 @@ public class PeppolDocumentTypeIdentifierParts extends PeppolGenericDocumentType
private final String m_sRootNS;
private final String m_sLocalName;
+ /**
+ * Convert the XML specific syntax elements back to a single syntax specific
+ * ID
+ *
+ * @param sRootNS
+ * The XML root element namespace URI. May neither be null
+ * nor empty.
+ * @param sLocalName
+ * The XML root element local name. May neither be null
+ * nor empty.
+ * @return The combination of rootNS + :: + localName
+ */
+ @Nonnull
+ @Nonempty
public static String createSyntaxSpecificID (@Nonnull @Nonempty final String sRootNS,
@Nonnull @Nonempty final String sLocalName)
{
@@ -95,22 +113,37 @@ public String toString ()
.getToString ();
}
+ public static boolean isSyntaxSpecificIDLookingLikeXML (@Nullable final String sSyntaxSpecificID)
+ {
+ if (StringHelper.hasText (sSyntaxSpecificID))
+ {
+ final int nIndex = sSyntaxSpecificID.indexOf (NAMESPACE_SEPARATOR);
+ if (nIndex >= 0)
+ {
+ // It's contains the separator and it's not the start and not the end
+ return nIndex > 0 && nIndex < sSyntaxSpecificID.length () - NAMESPACE_SEPARATOR.length ();
+ }
+ }
+ return false;
+ }
+
/**
- * Parse an OpenPeppol Document Type Identifier using the XML syntax.
+ * Split the provided syntax specific ID into the XML root element namespace
+ * URI and the XML root element local name.
*
- * @param sDocTypeIDValue
- * The document identifier value (without the scheme) to be split. May
- * neither be null
nor empty.
- * @return The non-null
Peppol identifier parts
- * @throws IllegalArgumentException
- * if the passed document identifier value does not match the
- * specifications
+ * @param sSyntaxSpecificID
+ * The syntax specific ID to parse. May neither be null
+ * nor empty.
+ * @param aResultConsumer
+ * The consumer that takes root namespace URI and local name as a
+ * callback.
+ * @since 9.6.2
*/
- @Nonnull
- public static PeppolDocumentTypeIdentifierParts extractFromString (@Nonnull @Nonempty final String sDocTypeIDValue)
+ public static void extractXMLSyntaxSpecificID (@Nonnull @Nonempty final String sSyntaxSpecificID,
+ @Nonnull final BiConsumer aResultConsumer)
{
- final PeppolGenericDocumentTypeIdentifierParts aGenericParts = PeppolGenericDocumentTypeIdentifierParts.extractFromString (sDocTypeIDValue);
- final String sSyntaxSpecificID = aGenericParts.getSyntaxSpecificID ();
+ ValueEnforcer.notEmpty (sSyntaxSpecificID, "SyntaxSpecificID");
+ ValueEnforcer.notNull (aResultConsumer, "ResultConsumer");
final ICommonsList aFirst = StringHelper.getExploded (NAMESPACE_SEPARATOR, sSyntaxSpecificID, 2);
if (aFirst.size () < 2)
@@ -129,8 +162,34 @@ public static PeppolDocumentTypeIdentifierParts extractFromString (@Nonnull @Non
sSyntaxSpecificID +
"' contains an empty local name!");
- return new PeppolDocumentTypeIdentifierParts (sRootNS,
- sLocalName,
+ aResultConsumer.accept (sRootNS, sLocalName);
+ }
+
+ /**
+ * Parse an OpenPeppol Document Type Identifier using the XML syntax.
+ *
+ * @param sDocTypeIDValue
+ * The document identifier value (without the scheme) to be split. May
+ * neither be null
nor empty.
+ * @return The non-null
Peppol identifier parts
+ * @throws IllegalArgumentException
+ * if the passed document identifier value does not match the
+ * specifications
+ */
+ @Nonnull
+ public static PeppolDocumentTypeIdentifierParts extractFromString (@Nonnull @Nonempty final String sDocTypeIDValue)
+ {
+ final PeppolGenericDocumentTypeIdentifierParts aGenericParts = PeppolGenericDocumentTypeIdentifierParts.extractFromString (sDocTypeIDValue);
+
+ final Wrapper aRootNS = new Wrapper <> ();
+ final Wrapper aLocalName = new Wrapper <> ();
+ extractXMLSyntaxSpecificID (aGenericParts.getSyntaxSpecificID (), (ns, ln) -> {
+ aRootNS.set (ns);
+ aLocalName.set (ln);
+ });
+
+ return new PeppolDocumentTypeIdentifierParts (aRootNS.get (),
+ aLocalName.get (),
aGenericParts.getCustomizationID (),
aGenericParts.getVersion ());
}
diff --git a/peppol-id/src/test/java/com/helger/peppolid/peppol/doctype/PeppolDocumentTypeIdentifierPartsTest.java b/peppol-id/src/test/java/com/helger/peppolid/peppol/doctype/PeppolDocumentTypeIdentifierPartsTest.java
index da8db570..70309106 100644
--- a/peppol-id/src/test/java/com/helger/peppolid/peppol/doctype/PeppolDocumentTypeIdentifierPartsTest.java
+++ b/peppol-id/src/test/java/com/helger/peppolid/peppol/doctype/PeppolDocumentTypeIdentifierPartsTest.java
@@ -17,7 +17,9 @@
package com.helger.peppolid.peppol.doctype;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
@@ -181,4 +183,14 @@ public void testList () throws IOException
});
}
}
+
+ @Test
+ public void testIsSyntaxSpecificIDLookingLikeXML ()
+ {
+ assertTrue (PeppolDocumentTypeIdentifierParts.isSyntaxSpecificIDLookingLikeXML ("a::b"));
+ assertTrue (PeppolDocumentTypeIdentifierParts.isSyntaxSpecificIDLookingLikeXML ("root::local"));
+ assertFalse (PeppolDocumentTypeIdentifierParts.isSyntaxSpecificIDLookingLikeXML ("root:local"));
+ assertFalse (PeppolDocumentTypeIdentifierParts.isSyntaxSpecificIDLookingLikeXML ("::local"));
+ assertFalse (PeppolDocumentTypeIdentifierParts.isSyntaxSpecificIDLookingLikeXML ("root::"));
+ }
}