This is an automated email from the ASF dual-hosted git repository.

ppkarwasz pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/commons-xml.git

commit d1d360b66f31cc503b960c3d9d04125b16c3a8a6
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Thu Apr 23 00:06:16 2026 +0200

    Initial implementation
    
    Introduce the basic project structure (Maven POM, README, license and 
notice files, .gitignore). No source code yet.
    
    Assisted-By: Claude Opus 4.7 (1M context) <[email protected]>
---
 .gitignore |  22 +++++----
 NOTICE.txt |   5 ++
 README.md  | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 pom.xml    | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 323 insertions(+), 11 deletions(-)

diff --git a/.gitignore b/.gitignore
index 91824e5..b7187a4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,23 +1,25 @@
-target/
+# Build output
+target
 pom.xml.tag
 pom.xml.releaseBackup
 pom.xml.versionsBackup
 pom.xml.next
 release.properties
-
 site-content
-/.classpath
-/.project
-/.settings/
 
-# Ignore IntelliJ files
-/.idea/
-*.iml
+# Eclipse files
+.project
+.classpath
+.settings/
 /bin/
 
-# Ignore Visual Studio code files
+# Visual Studio code files
 /.vscode/
 
-# NetBeans files
+# IntelliJ IDEA files
+.idea/
+*.iml
+
+# NetBeans files files
 nb-configuration.xml
 nbactions.xml
diff --git a/NOTICE.txt b/NOTICE.txt
new file mode 100644
index 0000000..23f38ef
--- /dev/null
+++ b/NOTICE.txt
@@ -0,0 +1,5 @@
+Apache Commons XML Factory
+Copyright 2026 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (https://www.apache.org/).
diff --git a/README.md b/README.md
index 0082ff5..9bcec33 100644
--- a/README.md
+++ b/README.md
@@ -14,4 +14,147 @@
  See the License for the specific language governing permissions and
  limitations under the License.
 -->
-More to come soon...
+
+# Apache Commons XML Factory
+
+> [!WARNING]
+> This is a draft of a new [Apache Commons](https://commons.apache.org) 
project base on
+> [this 
proposal](https://lists.apache.org/thread/b2tjc15vjkgsrxxkc8phlnt6801hx4xz).
+> 
+> It is **not** an official Apache Commons library yet.
+
+Secure-by-default JAXP factory creation for Java.
+A single method call returns a hardened JAXP factory that can be used to 
**safely** parse XML files.
+
+## Why
+
+Any Java library that parses XML has to harden JAXP before handing a factory 
to user code, and every library ends up
+copy-pasting the same hardening snippet. The snippet is fragile: the 
attributes and features needed to harden a factory
+are not standardised, each JAXP implementation exposes a slightly different 
set, and setting an unknown one throws an
+exception that callers routinely swallow. Writing this block correctly for 
every implementation is real work, and
+duplicating it across projects means every project owns the maintenance burden 
on its own.
+
+Defaults are also uneven. The stock JDK SAX and DOM parsers already prevent 
external entity resolution through
+`FEATURE_SECURE_PROCESSING`, and JAXP 1.5 conformant implementations ship 
reasonable defaults for most attacks. Others,
+such as standalone Xerces, Woodstox, or Saxon's TrAX, need further 
configuration before they reach the same baseline. A
+library author has no control over which implementation is on the classpath at 
runtime, so the effective security
+posture of their code depends on a deployment decision made elsewhere.
+
+This library provides that baseline. Each `XmlFactories` call returns a fresh 
factory hardened by a provider-specific
+SPI, so the returned object behaves the same way security-wise regardless of 
which JAXP implementation resolved.
+Security becomes a property of the call, not of the classpath, and there is 
one place to update when a new hardening
+setting becomes available or a default changes.
+
+## Usage
+
+Add the library to your build:
+
+```xml
+<dependency>
+  <groupId>org.apache.commons</groupId>
+  <artifactId>commons-xml-factory</artifactId>
+  <version>0.1.0</version>
+</dependency>
+```
+
+Every method on `XmlFactories` returns a fresh, hardened factory. Pick the one 
that matches the API you already use; no
+other configuration is required. On hardened factories any attempt to resolve 
an external resource (DTD, entity, schema,
+stylesheet) is blocked, and DOCTYPE input is rejected wherever the underlying 
implementation allows it.
+
+### Supported implementations
+
+Out of the box the library recognises the stock JDK JAXP implementations, 
Apache Xerces 2.x, Woodstox, and Saxon-HE. If
+a factory resolves to an implementation not covered by any bundled or 
registered provider, every `XmlFactories` method
+throws `UnsupportedXmlImplementationException`.
+
+Support for additional implementations can be plugged in by publishing an
+`org.apache.commons.xml.factory.spi.XmlProvider` through the standard Java 
`ServiceLoader` mechanism. Bundled providers
+always take precedence, so a third-party provider cannot hijack hardening for 
a factory class this library already
+supports.
+
+**DOM parsing** via `DocumentBuilderFactory`:
+
+```java
+import org.w3c.dom.Document;
+import org.apache.commons.xml.factory.XmlFactories;
+
+Document doc = 
XmlFactories.newDocumentBuilderFactory().newDocumentBuilder().parse(inputStream);
+```
+
+**SAX parsing** via `SAXParserFactory`:
+
+```java
+import org.apache.commons.xml.factory.XmlFactories;
+
+XmlFactories.newSAXParserFactory().newSAXParser().parse(inputStream, 
myDefaultHandler);
+```
+
+**Streaming (StAX) parsing** via `XMLInputFactory`:
+
+```java
+import javax.xml.stream.XMLStreamReader;
+import org.apache.commons.xml.factory.XmlFactories;
+
+XMLStreamReader reader = 
XmlFactories.newXMLInputFactory().createXMLStreamReader(inputStream);
+```
+
+**XSLT transforms** via `TransformerFactory`:
+
+```java
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.transform.stream.StreamResult;
+import org.apache.commons.xml.factory.XmlFactories;
+
+XmlFactories.newTransformerFactory()
+        .newTransformer(new StreamSource(stylesheet))
+        .transform(new StreamSource(inputStream), new 
StreamResult(outputStream));
+```
+
+**XPath queries** via `XPathFactory`:
+
+```java
+import javax.xml.xpath.XPathConstants;
+import org.w3c.dom.NodeList;
+import org.apache.commons.xml.factory.XmlFactories;
+
+NodeList hits = (NodeList) XmlFactories.newXPathFactory()
+        .newXPath()
+        .evaluate("//item", doc, XPathConstants.NODESET);
+```
+
+**W3C XML Schema validation** via `SchemaFactory`:
+
+```java
+import javax.xml.transform.stream.StreamSource;
+import org.apache.commons.xml.factory.XmlFactories;
+
+XmlFactories.newSchemaFactory()
+        .newSchema(new StreamSource(xsdStream))
+        .newValidator()
+        .validate(new StreamSource(inputStream));
+```
+
+### Stylesheets and schemas
+
+The hardening applies to documents parsed through the returned factory. 
Stylesheets given to
+`TransformerFactory.newTransformer(Source)` and schemas given to 
`SchemaFactory.newSchema(Source)` are read by a parser
+the implementation picks internally, and that parser may not be hardened 
(Saxon's TrAX is one such case, see Building
+below). Treat stylesheets and schemas as trusted input, or pre-parse them 
through a hardened `XmlFactories` parser and
+pass the result as a `DOMSource` or `SAXSource`.
+
+### Caching and thread-safety
+
+There is no caching or pooling inside `XmlFactories`; callers on a hot path 
are responsible for their own caching. The
+returned factories inherit the thread-safety properties of the underlying JAXP 
implementation, which in practice means
+they are not thread-safe. Create a new factory per thread or synchronise 
externally.
+
+## Building
+
+Building requires a Java JDK and [Apache Maven](https://maven.apache.org/).
+The required Java version is found in the `pom.xml` as the 
`maven.compiler.source` property.
+
+From a command shell, run `mvn` without arguments to invoke the default Maven 
goal to run all tests and checks
+
+## Licensing
+
+Licensed under the Apache License, Version 2.0. See `LICENSE.txt` and 
`NOTICE.txt`.
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..6264ec5
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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
+
+      https://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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
https://maven.apache.org/maven-v4_0_0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.commons</groupId>
+    <artifactId>commons-parent</artifactId>
+    <version>98</version>
+  </parent>
+  <artifactId>commons-xml-factory</artifactId>
+  <version>0.1.0-SNAPSHOT</version>
+  <name>Apache Commons XML Factory</name>
+  <url>https://commons.apache.org/proper/commons-xml-factory/</url>
+  <inceptionYear>2026</inceptionYear>
+  <description>Apache Commons XML Factory provides secure-by-default JAXP 
factory creation, abstracting over
+    implementation-specific XXE hardening differences between the stock JDK 
and external JAXP implementations
+    (Apache Xerces, Woodstox, Saxon-HE).</description>
+
+  <properties>
+    <!-- Release-related properties -->
+    <commons.release.version>0.1.0</commons.release.version>
+    <commons.release.desc>(Java 8+)</commons.release.desc>
+    <commons.rc.version>RC1</commons.rc.version>
+    <!-- Not relevant for first release: reenable after 0.1.0 and reenable 
japicmp
+    <commons.bc.version>0.1.0</commons.bc.version> -->
+    <japicmp.skip>true</japicmp.skip>
+    <commons.release.next>0.1.1</commons.release.next>
+    <commons.componentid>xml-factory</commons.componentid>
+    <commons.packageId>xml.factory</commons.packageId>
+    
<project.build.outputTimestamp>2026-04-22T00:00:00Z</project.build.outputTimestamp>
+
+    <!-- JIRA coordinates (to be assigned) -->
+    <commons.jira.id>COMMONSXMLFACTORY</commons.jira.id>
+    <commons.jira.pid>12300000</commons.jira.pid>
+
+    <!-- Java baseline -->
+    <maven.compiler.source>1.8</maven.compiler.source>
+    <maven.compiler.target>1.8</maven.compiler.target>
+
+    <!-- Optional JAXP implementations used by bundled providers. -->
+    <commons.xerces.version>2.12.2</commons.xerces.version>
+    <commons.woodstox.version>7.1.1</commons.woodstox.version>
+    <commons.saxon.version>12.9</commons.saxon.version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.junit.jupiter</groupId>
+      <artifactId>junit-jupiter</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <defaultGoal>clean verify</defaultGoal>
+    <plugins>
+
+      <!--
+        Run the test suite four times, each with exactly one JAXP 
implementation on the classpath:
+
+          - test-stockjdk: stock JDK factories only
+          - test-xerces:   stock JDK + external Apache Xerces
+          - test-woodstox: stock JDK + Woodstox (StAX)
+          - test-saxon:    stock JDK + Saxon-HE (TrAX, XPath)
+      -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-test</id>
+            <phase>none</phase>
+          </execution>
+          <execution>
+            <id>test-stockjdk</id>
+            <goals><goal>test</goal></goals>
+            <configuration>
+              
<reportsDirectory>${project.build.directory}/surefire-reports/stockjdk</reportsDirectory>
+            </configuration>
+          </execution>
+          <execution>
+            <id>test-xerces</id>
+            <goals><goal>test</goal></goals>
+            <configuration>
+              
<reportsDirectory>${project.build.directory}/surefire-reports/xerces</reportsDirectory>
+              <additionalClassPathDependencies>
+                <dependency>
+                  <groupId>xerces</groupId>
+                  <artifactId>xercesImpl</artifactId>
+                  <version>${commons.xerces.version}</version>
+                </dependency>
+              </additionalClassPathDependencies>
+            </configuration>
+          </execution>
+          <execution>
+            <id>test-woodstox</id>
+            <goals><goal>test</goal></goals>
+            <configuration>
+              
<reportsDirectory>${project.build.directory}/surefire-reports/woodstox</reportsDirectory>
+              <additionalClassPathDependencies>
+                <dependency>
+                  <groupId>com.fasterxml.woodstox</groupId>
+                  <artifactId>woodstox-core</artifactId>
+                  <version>${commons.woodstox.version}</version>
+                </dependency>
+              </additionalClassPathDependencies>
+            </configuration>
+          </execution>
+          <execution>
+            <id>test-saxon</id>
+            <goals><goal>test</goal></goals>
+            <configuration>
+              
<reportsDirectory>${project.build.directory}/surefire-reports/saxon</reportsDirectory>
+              <additionalClassPathDependencies>
+                <dependency>
+                  <groupId>net.sf.saxon</groupId>
+                  <artifactId>Saxon-HE</artifactId>
+                  <version>${commons.saxon.version}</version>
+                </dependency>
+              </additionalClassPathDependencies>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.moditect</groupId>
+        <artifactId>moditect-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>add-module-infos</id>
+            <configuration>
+              <module>
+                <moduleInfo>
+                  <exports>
+                    !*.internal;
+                    *;
+                  </exports>
+                </moduleInfo>
+              </module>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>

Reply via email to