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

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-text.git


The following commit(s) were added to refs/heads/master by this push:
     new 052f1294 Set SecureProcessing feature in XmlStringLookup by default.
052f1294 is described below

commit 052f1294daad65da8f0c191e6e2f81fe3897f6b6
Author: Gary Gregory <[email protected]>
AuthorDate: Sat May 6 09:57:28 2023 -0400

    Set SecureProcessing feature in XmlStringLookup by default.
    
    Add StringLookupFactory.xmlStringLookup(Pair<String, Boolean>...)
---
 pom.xml                                            |  6 ++--
 src/changes/changes.xml                            |  4 ++-
 .../commons/text/lookup/StringLookupFactory.java   | 39 ++++++++++++++++++++++
 .../commons/text/lookup/XmlStringLookup.java       | 35 +++++++++++++++----
 4 files changed, 74 insertions(+), 10 deletions(-)

diff --git a/pom.xml b/pom.xml
index e39603bb..176f0ca8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
     <version>56</version>
   </parent>
   <artifactId>commons-text</artifactId>
-  <version>1.10.1-SNAPSHOT</version>
+  <version>1.11.0-SNAPSHOT</version>
   <name>Apache Commons Text</name>
   <description>Apache Commons Text is a library focused on algorithms working 
on strings.</description>
   <url>https://commons.apache.org/proper/commons-text</url>
@@ -38,7 +38,7 @@
     <commons.packageId>text</commons.packageId>
     <commons.module.name>org.apache.commons.text</commons.module.name>
 
-    <commons.release.version>1.10.0</commons.release.version>
+    <commons.release.version>1.11.0</commons.release.version>
     <commons.release.desc>(Java 8+)</commons.release.desc>
 
     <commons.jira.id>TEXT</commons.jira.id>
@@ -64,7 +64,7 @@
     <jmh.version>1.36</jmh.version>
 
     <!-- Commons Release Plugin -->
-    <commons.bc.version>1.9</commons.bc.version>
+    <commons.bc.version>1.10.0</commons.bc.version>
     <commons.rc.version>RC1</commons.rc.version>
     <commons.release.isDistModule>true</commons.release.isDistModule>
     
<commons.distSvnStagingUrl>scm:svn:https://dist.apache.org/repos/dist/dev/commons/${commons.componentid}</commons.distSvnStagingUrl>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 5a8f57b4..7b25d72d 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -46,7 +46,7 @@ The <action> type attribute can be add,update,fix,remove.
     <title>Apache Commons Text Changes</title>
   </properties>
   <body>
-  <release version="1.10.1" date="20YY-MM-DD" description="Release 1.10.1. 
Requires Java 8.">
+  <release version="1.11.0" date="20YY-MM-DD" description="Release 1.10.1. 
Requires Java 8.">
     <!-- FIX -->
     <action issue="TEXT-219" type="fix" dev="aherbert" due-to="Jaap 
Sperling">Fix StringTokenizer.getTokenList to return an independent modifiable 
list</action>
     <action                  type="fix" dev="aherbert" due-to="James Nord">Fix 
Javadoc for StringEscapeUtils.escapeHtml4 #382</action>
@@ -58,6 +58,8 @@ The <action> type attribute can be add,update,fix,remove.
     <action                  type="fix" dev="ggregory" due-to="Gary 
Gregory">Add and use a package-private singleton for 
JaroWinklerSimilarity.</action>
     <action                  type="fix" dev="ggregory" due-to="Gary 
Gregory">Add and use a package-private singleton for JaccardSimilarity.</action>
     <!-- ADD -->
+    <action issue="TEXT-224" type="add" dev="ggregory" due-to="PJ Fanning, 
Gary Gregory">Set SecureProcessing feature in XmlStringLookup by 
default.</action>
+    <action issue="TEXT-224" type="add" dev="ggregory" due-to="Gary 
Gregory">Add StringLookupFactory.xmlStringLookup(Pair&lt;String, 
Boolean&gt;...).</action>
     <!-- UPDATE -->
     <action                  type="update" dev="ggregory" 
due-to="Dependabot">Bump actions/cache from 3.0.8 to 3.0.10 #361, #365.</action>
     <action                  type="update" dev="ggregory" 
due-to="Dependabot">Bump actions/setup-java from 3 to 3.5.1.</action>
diff --git 
a/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java 
b/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java
index a2a0abd1..8e826e04 100644
--- a/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java
+++ b/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java
@@ -27,6 +27,9 @@ import java.util.Properties;
 import java.util.function.BiFunction;
 import java.util.function.Function;
 
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.commons.text.StringSubstitutor;
 
 /**
@@ -1315,4 +1318,40 @@ public final class StringLookupFactory {
     public StringLookup xmlStringLookup() {
         return XmlStringLookup.INSTANCE;
     }
+
+    /**
+     * Returns the XmlStringLookup singleton instance.
+     * <p>
+     * Looks up the value for the key in the format "DocumentPath:XPath".
+     * </p>
+     * <p>
+     * For example: "com/domain/document.xml:/path/to/node".
+     * </p>
+     * <p>
+     * Using a {@link StringLookup} from the {@link StringLookupFactory}:
+     * </p>
+     *
+     * <pre>
+     * 
StringLookupFactory.INSTANCE.xmlStringLookup().lookup("com/domain/document.xml:/path/to/node");
+     * </pre>
+     * <p>
+     * Using a {@link StringSubstitutor}:
+     * </p>
+     *
+     * <pre>
+     * StringSubstitutor.createInterpolator().replace("... 
${xml:com/domain/document.xml:/path/to/node} ..."));
+     * </pre>
+     * <p>
+     * The above examples convert {@code 
"com/domain/document.xml:/path/to/node"} to the value of the XPath in the XML
+     * document.
+     * </p>
+     *
+     * @param xPathFactoryFeatures XPathFactory features to set.
+     * @return The XmlStringLookup singleton instance.
+     * @see XPathFactory#setFeature(String, boolean)
+     * @since 1.11.0
+     */
+    public StringLookup xmlStringLookup(@SuppressWarnings("unchecked") 
Pair<String, Boolean>... xPathFactoryFeatures) {
+        return new XmlStringLookup(xPathFactoryFeatures);
+    }
 }
diff --git a/src/main/java/org/apache/commons/text/lookup/XmlStringLookup.java 
b/src/main/java/org/apache/commons/text/lookup/XmlStringLookup.java
index 12aa5e56..2c6c73dc 100644
--- a/src/main/java/org/apache/commons/text/lookup/XmlStringLookup.java
+++ b/src/main/java/org/apache/commons/text/lookup/XmlStringLookup.java
@@ -20,10 +20,13 @@ package org.apache.commons.text.lookup;
 import java.io.InputStream;
 import java.nio.file.Files;
 import java.nio.file.Paths;
+import java.util.Objects;
 
+import javax.xml.XMLConstants;
 import javax.xml.xpath.XPathFactory;
 
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
 import org.xml.sax.InputSource;
 
 /**
@@ -39,16 +42,32 @@ import org.xml.sax.InputSource;
  */
 final class XmlStringLookup extends AbstractStringLookup {
 
+    /**
+     * Defines default XPath factory features.
+     */
+    @SuppressWarnings("unchecked")
+    private static final Pair<String, Boolean>[] DEFAULT_FEATURES = new Pair[] 
{
+            Pair.of(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE) };
+
     /**
      * Defines the singleton for this class.
      */
-    static final XmlStringLookup INSTANCE = new XmlStringLookup();
+    static final XmlStringLookup INSTANCE = new 
XmlStringLookup(DEFAULT_FEATURES);
+
+    /**
+     * Defines XPath factory features.
+     */
+    private final Pair<String, Boolean>[] xPathFactoryFeatures;
 
     /**
      * No need to build instances for now.
+     *
+     * @param xPathFactoryFeatures XPathFactory features to set.
+     * @see XPathFactory#setFeature(String, boolean)
      */
-    private XmlStringLookup() {
-        // empty
+    @SafeVarargs
+    XmlStringLookup(final Pair<String, Boolean>... xPathFactoryFeatures) {
+        this.xPathFactoryFeatures = 
Objects.requireNonNull(xPathFactoryFeatures, "xPathFfactoryFeatures");
     }
 
     /**
@@ -69,15 +88,19 @@ final class XmlStringLookup extends AbstractStringLookup {
         final int keyLen = keys.length;
         if (keyLen != 2) {
             throw IllegalArgumentExceptions.format("Bad XML key format [%s]; 
expected format is DocumentPath:XPath.",
-                key);
+                    key);
         }
         final String documentPath = keys[0];
         final String xpath = StringUtils.substringAfter(key, SPLIT_CH);
         try (InputStream inputStream = 
Files.newInputStream(Paths.get(documentPath))) {
-            return XPathFactory.newInstance().newXPath().evaluate(xpath, new 
InputSource(inputStream));
+            final XPathFactory factory = XPathFactory.newInstance();
+            for (final Pair<String, Boolean> p : xPathFactoryFeatures) {
+                factory.setFeature(p.getKey(), p.getValue());
+            }
+            return factory.newXPath().evaluate(xpath, new 
InputSource(inputStream));
         } catch (final Exception e) {
             throw IllegalArgumentExceptions.format(e, "Error looking up XML 
document [%s] and XPath [%s].",
-                documentPath, xpath);
+                    documentPath, xpath);
         }
     }
 

Reply via email to