001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 018package org.apache.commons.text.lookup; 019 020import java.nio.charset.StandardCharsets; 021import java.util.Base64; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.Locale; 025import java.util.Map; 026import java.util.Properties; 027import java.util.function.BiFunction; 028import java.util.function.Function; 029 030import org.apache.commons.text.StringSubstitutor; 031 032/** 033 * Create instances of string lookups or access singleton string lookups implemented in this package. 034 * <p> 035 * The "classic" look up is {@link #mapStringLookup(Map)}. 036 * </p> 037 * <p> 038 * The methods for variable interpolation (A.K.A. variable substitution) are: 039 * </p> 040 * <ul> 041 * <li>{@link #interpolatorStringLookup()}.</li> 042 * <li>{@link #interpolatorStringLookup(Map)}.</li> 043 * <li>{@link #interpolatorStringLookup(StringLookup)}.</li> 044 * <li>{@link #interpolatorStringLookup(Map, StringLookup, boolean)}.</li> 045 * </ul> 046 * <p> 047 * Unless explicitly requested otherwise, a set of default lookups are included for convenience with these 048 * variable interpolation methods. These defaults are listed in the table below. However, the exact lookups 049 * included can be configured through the use of the {@value #DEFAULT_STRING_LOOKUPS_PROPERTY} system property. 050 * If present, this system property will be parsed as a comma-separated list of lookup names, with the names 051 * being those defined by the {@link DefaultStringLookup} enum. For example, setting this system property to 052 * {@code "BASE64_ENCODER,ENVIRONMENT"} will only include the 053 * {@link DefaultStringLookup#BASE64_ENCODER BASE64_ENCODER} and {@link DefaultStringLookup#ENVIRONMENT ENVIRONMENT} 054 * lookups. Setting the property to the empty string will cause no defaults to be configured. 055 * Note that not all lookups defined here and in {@link DefaultStringLookup} are included by default. 056 * Specifically, lookups that can execute code (e.g., {@link DefaultStringLookup#SCRIPT SCRIPT}) and those 057 * that can result in contact with remote servers (e.g., {@link DefaultStringLookup#URL URL} and 058 * {@link DefaultStringLookup#DNS DNS}) are not included by default. The current set of default lookups can 059 * be accessed directly with {@link #addDefaultStringLookups(Map)}. 060 * </p> 061 * <table> 062 * <caption>Default String Lookups</caption> 063 * <tr> 064 * <th>Key</th> 065 * <th>Interface</th> 066 * <th>Factory Method</th> 067 * <th>Since</th> 068 * </tr> 069 * <tr> 070 * <td>{@value #KEY_BASE64_DECODER}</td> 071 * <td>{@link StringLookup}</td> 072 * <td>{@link #base64DecoderStringLookup()}</td> 073 * <td>1.6</td> 074 * </tr> 075 * <tr> 076 * <td>{@value #KEY_BASE64_ENCODER}</td> 077 * <td>{@link StringLookup}</td> 078 * <td>{@link #base64EncoderStringLookup()}</td> 079 * <td>1.6</td> 080 * </tr> 081 * <tr> 082 * <td>{@value #KEY_CONST}</td> 083 * <td>{@link StringLookup}</td> 084 * <td>{@link #constantStringLookup()}</td> 085 * <td>1.5</td> 086 * </tr> 087 * <tr> 088 * <td>{@value #KEY_DATE}</td> 089 * <td>{@link StringLookup}</td> 090 * <td>{@link #dateStringLookup()}</td> 091 * <td>1.5</td> 092 * </tr> 093 * <tr> 094 * <td>{@value #KEY_ENV}</td> 095 * <td>{@link StringLookup}</td> 096 * <td>{@link #environmentVariableStringLookup()}</td> 097 * <td>1.3</td> 098 * </tr> 099 * <tr> 100 * <td>{@value #KEY_FILE}</td> 101 * <td>{@link StringLookup}</td> 102 * <td>{@link #fileStringLookup()}</td> 103 * <td>1.5</td> 104 * </tr> 105 * <tr> 106 * <td>{@value #KEY_JAVA}</td> 107 * <td>{@link StringLookup}</td> 108 * <td>{@link #javaPlatformStringLookup()}</td> 109 * <td>1.5</td> 110 * </tr> 111 * <tr> 112 * <td>{@value #KEY_LOCALHOST}</td> 113 * <td>{@link StringLookup}</td> 114 * <td>{@link #localHostStringLookup()}</td> 115 * <td>1.3</td> 116 * </tr> 117 * <tr> 118 * <td>{@value #KEY_PROPERTIES}</td> 119 * <td>{@link StringLookup}</td> 120 * <td>{@link #propertiesStringLookup()}</td> 121 * <td>1.5</td> 122 * </tr> 123 * <tr> 124 * <td>{@value #KEY_RESOURCE_BUNDLE}</td> 125 * <td>{@link StringLookup}</td> 126 * <td>{@link #resourceBundleStringLookup()}</td> 127 * <td>1.6</td> 128 * </tr> 129 * <tr> 130 * <td>{@value #KEY_SYS}</td> 131 * <td>{@link StringLookup}</td> 132 * <td>{@link #systemPropertyStringLookup()}</td> 133 * <td>1.3</td> 134 * </tr> 135 * <tr> 136 * <td>{@value #KEY_URL_DECODER}</td> 137 * <td>{@link StringLookup}</td> 138 * <td>{@link #urlDecoderStringLookup()}</td> 139 * <td>1.5</td> 140 * </tr> 141 * <tr> 142 * <td>{@value #KEY_URL_ENCODER}</td> 143 * <td>{@link StringLookup}</td> 144 * <td>{@link #urlEncoderStringLookup()}</td> 145 * <td>1.5</td> 146 * </tr> 147 * <tr> 148 * <td>{@value #KEY_XML}</td> 149 * <td>{@link StringLookup}</td> 150 * <td>{@link #xmlStringLookup()}</td> 151 * <td>1.5</td> 152 * </tr> 153 * </table> 154 * 155 * <table> 156 * <caption>Additional String Lookups (not included by default)</caption> 157 * <tr> 158 * <th>Key</th> 159 * <th>Interface</th> 160 * <th>Factory Method</th> 161 * <th>Since</th> 162 * </tr> 163 * <tr> 164 * <td>{@value #KEY_DNS}</td> 165 * <td>{@link StringLookup}</td> 166 * <td>{@link #dnsStringLookup()}</td> 167 * <td>1.8</td> 168 * </tr> 169 * <tr> 170 * <td>{@value #KEY_URL}</td> 171 * <td>{@link StringLookup}</td> 172 * <td>{@link #urlStringLookup()}</td> 173 * <td>1.5</td> 174 * </tr> 175 * <tr> 176 * <td>{@value #KEY_SCRIPT}</td> 177 * <td>{@link StringLookup}</td> 178 * <td>{@link #scriptStringLookup()}</td> 179 * <td>1.5</td> 180 * </tr> 181 * </table> 182 * 183 * <p> 184 * This class also provides functional lookups used as building blocks for other lookups. 185 * <table> 186 * <caption>Functional String Lookups</caption> 187 * <tr> 188 * <th>Interface</th> 189 * <th>Factory Method</th> 190 * <th>Since</th> 191 * </tr> 192 * <tr> 193 * <td>{@link BiStringLookup}</td> 194 * <td>{@link #biFunctionStringLookup(BiFunction)}</td> 195 * <td>1.9</td> 196 * </tr> 197 * <tr> 198 * <td>{@link StringLookup}</td> 199 * <td>{@link #functionStringLookup(Function)}</td> 200 * <td>1.9</td> 201 * </tr> 202 * </table> 203 * 204 * @since 1.3 205 */ 206public final class StringLookupFactory { 207 208 /** 209 * Internal class used to construct the default {@link StringLookup} map used by 210 * {@link StringLookupFactory#addDefaultStringLookups(Map)}. 211 */ 212 static final class DefaultStringLookupsHolder { 213 214 /** Singleton instance, initialized with the system properties. */ 215 static final DefaultStringLookupsHolder INSTANCE = new DefaultStringLookupsHolder(System.getProperties()); 216 217 /** 218 * Add the key and string lookup from {@code lookup} to {@code map}, also adding any additional 219 * key aliases if needed. Keys are normalized using the {@link #toKey(String)} method. 220 * @param lookup lookup to add 221 * @param map map to add to 222 */ 223 private static void addLookup(final DefaultStringLookup lookup, final Map<String, StringLookup> map) { 224 map.put(toKey(lookup.getKey()), lookup.getStringLookup()); 225 226 if (DefaultStringLookup.BASE64_DECODER.equals(lookup)) { 227 // "base64" is deprecated in favor of KEY_BASE64_DECODER. 228 map.put(toKey("base64"), lookup.getStringLookup()); 229 } 230 } 231 232 /** 233 * Create the lookup map used when the user has requested no customization. 234 * @return default lookup map 235 */ 236 private static Map<String, StringLookup> createDefaultStringLookups() { 237 final Map<String, StringLookup> lookupMap = new HashMap<>(); 238 239 addLookup(DefaultStringLookup.BASE64_DECODER, lookupMap); 240 addLookup(DefaultStringLookup.BASE64_ENCODER, lookupMap); 241 addLookup(DefaultStringLookup.CONST, lookupMap); 242 addLookup(DefaultStringLookup.DATE, lookupMap); 243 addLookup(DefaultStringLookup.ENVIRONMENT, lookupMap); 244 addLookup(DefaultStringLookup.FILE, lookupMap); 245 addLookup(DefaultStringLookup.JAVA, lookupMap); 246 addLookup(DefaultStringLookup.LOCAL_HOST, lookupMap); 247 addLookup(DefaultStringLookup.PROPERTIES, lookupMap); 248 addLookup(DefaultStringLookup.RESOURCE_BUNDLE, lookupMap); 249 addLookup(DefaultStringLookup.SYSTEM_PROPERTIES, lookupMap); 250 addLookup(DefaultStringLookup.URL_DECODER, lookupMap); 251 addLookup(DefaultStringLookup.URL_ENCODER, lookupMap); 252 addLookup(DefaultStringLookup.XML, lookupMap); 253 254 return lookupMap; 255 } 256 257 /** 258 * Construct a lookup map by parsing the given string. The string is expected to contain 259 * comma or space-separated names of values from the {@link DefaultStringLookup} enum. If 260 * the given string is null or empty, an empty map is returned. 261 * @param str string to parse; may be null or empty 262 * @return lookup map parsed from the given string 263 */ 264 private static Map<String, StringLookup> parseStringLookups(final String str) { 265 final Map<String, StringLookup> lookupMap = new HashMap<>(); 266 267 try { 268 for (final String lookupName : str.split("[\\s,]+")) { 269 if (!lookupName.isEmpty()) { 270 addLookup(DefaultStringLookup.valueOf(lookupName.toUpperCase()), lookupMap); 271 } 272 } 273 } catch (IllegalArgumentException exc) { 274 throw new IllegalArgumentException("Invalid default string lookups definition: " + str, exc); 275 } 276 277 return lookupMap; 278 } 279 280 /** Default string lookup map. */ 281 private final Map<String, StringLookup> defaultStringLookups; 282 283 /** 284 * Construct a new instance initialized with the given properties. 285 * @param props initialization properties 286 */ 287 DefaultStringLookupsHolder(final Properties props) { 288 final Map<String, StringLookup> lookups = 289 props.containsKey(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY) 290 ? parseStringLookups(props.getProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY)) 291 : createDefaultStringLookups(); 292 293 defaultStringLookups = Collections.unmodifiableMap(lookups); 294 } 295 296 /** 297 * Get the default string lookups map. 298 * @return default string lookups map 299 */ 300 Map<String, StringLookup> getDefaultStringLookups() { 301 return defaultStringLookups; 302 } 303 } 304 305 /** 306 * Defines the singleton for this class. 307 */ 308 public static final StringLookupFactory INSTANCE = new StringLookupFactory(); 309 310 /** 311 * Decodes Base64 Strings. 312 * <p> 313 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 314 * </p> 315 * 316 * <pre> 317 * StringLookupFactory.INSTANCE.base64DecoderStringLookup().lookup("SGVsbG9Xb3JsZCE="); 318 * </pre> 319 * <p> 320 * Using a {@link StringSubstitutor}: 321 * </p> 322 * 323 * <pre> 324 * StringSubstitutor.createInterpolator().replace("... ${base64Decoder:SGVsbG9Xb3JsZCE=} ...")); 325 * </pre> 326 * <p> 327 * The above examples convert {@code "SGVsbG9Xb3JsZCE="} to {@code "HelloWorld!"}. 328 * </p> 329 */ 330 static final FunctionStringLookup<String> INSTANCE_BASE64_DECODER = FunctionStringLookup 331 .on(key -> new String(Base64.getDecoder().decode(key), StandardCharsets.ISO_8859_1)); 332 333 /** 334 * Encodes Base64 Strings. 335 * <p> 336 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 337 * </p> 338 * 339 * <pre> 340 * StringLookupFactory.INSTANCE.base64EncoderStringLookup().lookup("HelloWorld!"); 341 * </pre> 342 * <p> 343 * Using a {@link StringSubstitutor}: 344 * </p> 345 * 346 * <pre> 347 * StringSubstitutor.createInterpolator().replace("... ${base64Encoder:HelloWorld!} ...")); 348 * </pre> 349 * <p> 350 * The above examples convert {@code "HelloWorld!"} to {@code "SGVsbG9Xb3JsZCE="}. 351 * </p> 352 * Defines the singleton for this class. 353 */ 354 static final FunctionStringLookup<String> INSTANCE_BASE64_ENCODER = FunctionStringLookup 355 .on(key -> Base64.getEncoder().encodeToString(key.getBytes(StandardCharsets.ISO_8859_1))); 356 357 /** 358 * Looks up keys from environment variables. 359 * <p> 360 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 361 * </p> 362 * 363 * <pre> 364 * StringLookupFactory.INSTANCE.environmentVariableStringLookup().lookup("USER"); 365 * </pre> 366 * <p> 367 * Using a {@link StringSubstitutor}: 368 * </p> 369 * 370 * <pre> 371 * StringSubstitutor.createInterpolator().replace("... ${env:USER} ...")); 372 * </pre> 373 * <p> 374 * The above examples convert (on Linux) {@code "USER"} to the current user name. On Windows 10, you would use 375 * {@code "USERNAME"} to the same effect. 376 * </p> 377 */ 378 static final FunctionStringLookup<String> INSTANCE_ENVIRONMENT_VARIABLES = FunctionStringLookup.on(System::getenv); 379 380 /** 381 * Defines the FunctionStringLookup singleton that always returns null. 382 */ 383 static final FunctionStringLookup<String> INSTANCE_NULL = FunctionStringLookup.on(key -> null); 384 385 /** 386 * Defines the FunctionStringLookup singleton for looking up system properties. 387 */ 388 static final FunctionStringLookup<String> INSTANCE_SYSTEM_PROPERTIES = FunctionStringLookup.on(System::getProperty); 389 390 /** 391 * Default lookup key for interpolation {@value #KEY_BASE64_DECODER}. 392 * 393 * @since 1.6 394 */ 395 public static final String KEY_BASE64_DECODER = "base64Decoder"; 396 397 /** 398 * Default lookup key for interpolation {@value #KEY_BASE64_ENCODER}. 399 * 400 * @since 1.6 401 */ 402 public static final String KEY_BASE64_ENCODER = "base64Encoder"; 403 404 /** 405 * Default lookup key for interpolation {@value #KEY_CONST}. 406 * 407 * @since 1.6 408 */ 409 public static final String KEY_CONST = "const"; 410 411 /** 412 * Default lookup key for interpolation {@value #KEY_DATE}. 413 * 414 * @since 1.6 415 */ 416 public static final String KEY_DATE = "date"; 417 418 /** 419 * Default lookup key for interpolation {@value #KEY_DNS}. 420 * 421 * @since 1.8 422 */ 423 public static final String KEY_DNS = "dns"; 424 425 /** 426 * Default lookup key for interpolation {@value #KEY_ENV}. 427 * 428 * @since 1.6 429 */ 430 public static final String KEY_ENV = "env"; 431 432 /** 433 * Default lookup key for interpolation {@value #KEY_FILE}. 434 * 435 * @since 1.6 436 */ 437 public static final String KEY_FILE = "file"; 438 439 /** 440 * Default lookup key for interpolation {@value #KEY_JAVA}. 441 * 442 * @since 1.6 443 */ 444 public static final String KEY_JAVA = "java"; 445 446 /** 447 * Default lookup key for interpolation {@value #KEY_LOCALHOST}. 448 * 449 * @since 1.6 450 */ 451 public static final String KEY_LOCALHOST = "localhost"; 452 453 /** 454 * Default lookup key for interpolation {@value #KEY_PROPERTIES}. 455 * 456 * @since 1.6 457 */ 458 public static final String KEY_PROPERTIES = "properties"; 459 460 /** 461 * Default lookup key for interpolation {@value #KEY_RESOURCE_BUNDLE}. 462 * 463 * @since 1.6 464 */ 465 public static final String KEY_RESOURCE_BUNDLE = "resourceBundle"; 466 467 /** 468 * Default lookup key for interpolation {@value #KEY_SCRIPT}. 469 * 470 * @since 1.6 471 */ 472 public static final String KEY_SCRIPT = "script"; 473 474 /** 475 * Default lookup key for interpolation {@value #KEY_SYS}. 476 * 477 * @since 1.6 478 */ 479 public static final String KEY_SYS = "sys"; 480 481 /** 482 * Default lookup key for interpolation {@value #KEY_URL}. 483 * 484 * @since 1.6 485 */ 486 public static final String KEY_URL = "url"; 487 488 /** 489 * Default lookup key for interpolation {@value #KEY_URL_DECODER}. 490 * 491 * @since 1.6 492 */ 493 public static final String KEY_URL_DECODER = "urlDecoder"; 494 495 /** 496 * Default lookup key for interpolation {@value #KEY_URL_ENCODER}. 497 * 498 * @since 1.6 499 */ 500 public static final String KEY_URL_ENCODER = "urlEncoder"; 501 502 /** 503 * Default lookup key for interpolation {@value #KEY_XML}. 504 * 505 * @since 1.6 506 */ 507 public static final String KEY_XML = "xml"; 508 509 /** 510 * Name of the system property used to determine the string lookups added by the 511 * {@link #addDefaultStringLookups(Map)} method. Use of this property is only required 512 * in cases where the set of default lookups must be modified. (See the class documentation 513 * for details.) 514 * 515 * @since 1.10.0 516 */ 517 public static final String DEFAULT_STRING_LOOKUPS_PROPERTY = "org.apache.commons.text.lookup.StringLookupFactory.defaultStringLookups"; 518 519 /** 520 * Clears any static resources. 521 * 522 * @since 1.5 523 */ 524 public static void clear() { 525 ConstantStringLookup.clear(); 526 } 527 528 /** 529 * Get a string suitable for use as a key in the string lookup map. 530 * @param key string to convert to a string lookup map key 531 * @return string lookup map key 532 */ 533 static String toKey(final String key) { 534 return key.toLowerCase(Locale.ROOT); 535 } 536 537 /** 538 * Returns the given map if the input is non-null or an empty immutable map if the input is null. 539 * 540 * @param <K> the class of the map keys 541 * @param <V> the class of the map values 542 * @param map The map to test 543 * @return the given map if the input is non-null or an empty immutable map if the input is null. 544 */ 545 static <K, V> Map<K, V> toMap(final Map<K, V> map) { 546 return map == null ? Collections.emptyMap() : map; 547 } 548 549 /** 550 * No need to build instances for now. 551 */ 552 private StringLookupFactory() { 553 // empty 554 } 555 556 /** 557 * Adds the default string lookups for this class to {@code stringLookupMap}. The default string 558 * lookups are a set of built-in lookups added for convenience during string interpolation. The 559 * defaults may be configured using the {@value #DEFAULT_STRING_LOOKUPS_PROPERTY} system property. 560 * See the class documentation for details and a list of lookups. 561 * 562 * @param stringLookupMap the map of string lookups to edit. 563 * @since 1.5 564 */ 565 public void addDefaultStringLookups(final Map<String, StringLookup> stringLookupMap) { 566 if (stringLookupMap != null) { 567 stringLookupMap.putAll(DefaultStringLookupsHolder.INSTANCE.getDefaultStringLookups()); 568 } 569 } 570 571 /** 572 * Returns the Base64DecoderStringLookup singleton instance to decode Base64 strings. 573 * <p> 574 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 575 * </p> 576 * 577 * <pre> 578 * StringLookupFactory.INSTANCE.base64DecoderStringLookup().lookup("SGVsbG9Xb3JsZCE="); 579 * </pre> 580 * <p> 581 * Using a {@link StringSubstitutor}: 582 * </p> 583 * 584 * <pre> 585 * StringSubstitutor.createInterpolator().replace("... ${base64Decoder:SGVsbG9Xb3JsZCE=} ...")); 586 * </pre> 587 * <p> 588 * The above examples convert {@code "SGVsbG9Xb3JsZCE="} to {@code "HelloWorld!"}. 589 * </p> 590 * 591 * @return The Base64DecoderStringLookup singleton instance. 592 * @since 1.5 593 */ 594 public StringLookup base64DecoderStringLookup() { 595 return StringLookupFactory.INSTANCE_BASE64_DECODER; 596 } 597 598 /** 599 * Returns the Base64EncoderStringLookup singleton instance to encode strings to Base64. 600 * <p> 601 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 602 * </p> 603 * 604 * <pre> 605 * StringLookupFactory.INSTANCE.base64EncoderStringLookup().lookup("HelloWorld!"); 606 * </pre> 607 * <p> 608 * Using a {@link StringSubstitutor}: 609 * </p> 610 * 611 * <pre> 612 * StringSubstitutor.createInterpolator().replace("... ${base64Encoder:HelloWorld!} ...")); 613 * </pre> 614 * <p> 615 * The above examples convert {@code } to {@code "SGVsbG9Xb3JsZCE="}. 616 * </p> 617 * 618 * @return The Base64EncoderStringLookup singleton instance. 619 * @since 1.6 620 */ 621 public StringLookup base64EncoderStringLookup() { 622 return StringLookupFactory.INSTANCE_BASE64_ENCODER; 623 } 624 625 /** 626 * Returns the Base64DecoderStringLookup singleton instance to decode Base64 strings. 627 * <p> 628 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 629 * </p> 630 * 631 * <pre> 632 * StringLookupFactory.INSTANCE.base64DecoderStringLookup().lookup("SGVsbG9Xb3JsZCE="); 633 * </pre> 634 * <p> 635 * Using a {@link StringSubstitutor}: 636 * </p> 637 * 638 * <pre> 639 * StringSubstitutor.createInterpolator().replace("... ${base64Decoder:SGVsbG9Xb3JsZCE=} ...")); 640 * </pre> 641 * <p> 642 * The above examples convert {@code "SGVsbG9Xb3JsZCE="} to {@code "HelloWorld!"}. 643 * </p> 644 * 645 * @return The Base64DecoderStringLookup singleton instance. 646 * @since 1.5 647 * @deprecated Use {@link #base64DecoderStringLookup()}. 648 */ 649 @Deprecated 650 public StringLookup base64StringLookup() { 651 return StringLookupFactory.INSTANCE_BASE64_DECODER; 652 } 653 654 /** 655 * Returns a new function-based lookup where the request for a lookup is answered by applying the function with a 656 * lookup key. 657 * 658 * @param <R> the function return type. 659 * @param <U> the function's second parameter type. 660 * @param biFunction the function. 661 * @return a new MapStringLookup. 662 * @since 1.9 663 */ 664 public <R, U> BiStringLookup<U> biFunctionStringLookup(final BiFunction<String, U, R> biFunction) { 665 return BiFunctionStringLookup.on(biFunction); 666 } 667 668 /** 669 * Returns the ConstantStringLookup singleton instance to look up the value of a fully-qualified static final value. 670 * <p> 671 * Sometimes it is necessary in a configuration file to refer to a constant defined in a class. This can be done 672 * with this lookup implementation. Variable names must be in the format {@code apackage.AClass.AFIELD}. The 673 * {@code lookup(String)} method will split the passed in string at the last dot, separating the fully qualified 674 * class name and the name of the constant (i.e. <b>static final</b>) member field. Then the class is loaded and the 675 * field's value is obtained using reflection. 676 * </p> 677 * <p> 678 * Once retrieved values are cached for fast access. This class is thread-safe. It can be used as a standard (i.e. 679 * global) lookup object and serve multiple clients concurrently. 680 * </p> 681 * <p> 682 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 683 * </p> 684 * 685 * <pre> 686 * StringLookupFactory.INSTANCE.constantStringLookup().lookup("java.awt.event.KeyEvent.VK_ESCAPE"); 687 * </pre> 688 * <p> 689 * Using a {@link StringSubstitutor}: 690 * </p> 691 * 692 * <pre> 693 * StringSubstitutor.createInterpolator().replace("... ${const:java.awt.event.KeyEvent.VK_ESCAPE} ...")); 694 * </pre> 695 * <p> 696 * The above examples convert {@code java.awt.event.KeyEvent.VK_ESCAPE} to {@code "27"}. 697 * </p> 698 * 699 * @return The ConstantStringLookup singleton instance. 700 * @since 1.5 701 */ 702 public StringLookup constantStringLookup() { 703 return ConstantStringLookup.INSTANCE; 704 } 705 706 /** 707 * Returns the DateStringLookup singleton instance to format the current date with the format given in the key in a 708 * format compatible with {@link java.text.SimpleDateFormat}. 709 * <p> 710 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 711 * </p> 712 * 713 * <pre> 714 * StringLookupFactory.INSTANCE.dateStringLookup().lookup("yyyy-MM-dd"); 715 * </pre> 716 * <p> 717 * Using a {@link StringSubstitutor}: 718 * </p> 719 * 720 * <pre> 721 * StringSubstitutor.createInterpolator().replace("... ${date:yyyy-MM-dd} ...")); 722 * </pre> 723 * <p> 724 * The above examples convert {@code "yyyy-MM-dd"} to todays's date, for example, {@code "2019-08-04"}. 725 * </p> 726 * 727 * @return The DateStringLookup singleton instance. 728 */ 729 public StringLookup dateStringLookup() { 730 return DateStringLookup.INSTANCE; 731 } 732 733 /** 734 * Returns the DnsStringLookup singleton instance where the lookup key is one of: 735 * <ul> 736 * <li><b>name</b>: for the local host name, for example {@code EXAMPLE} but also {@code EXAMPLE.apache.org}.</li> 737 * <li><b>canonical-name</b>: for the local canonical host name, for example {@code EXAMPLE.apache.org}.</li> 738 * <li><b>address</b>: for the local host address, for example {@code 192.168.56.1}.</li> 739 * </ul> 740 * 741 * <p> 742 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 743 * </p> 744 * 745 * <pre> 746 * StringLookupFactory.INSTANCE.dnsStringLookup().lookup("address|apache.org"); 747 * </pre> 748 * <p> 749 * When used through a {@link StringSubstitutor}, this lookup must either be added programmatically 750 * (as below) or enabled as a default lookup using the {@value #DEFAULT_STRING_LOOKUPS_PROPERTY} system property 751 * (see class documentation). 752 * </p> 753 * 754 * <pre> 755 * Map<String, StringLookup> lookupMap = new HashMap<>(); 756 * lookupMap.put("dns", StringLookupFactory.INSTANCE.dnsStringLookup()); 757 * 758 * StringLookup variableResolver = StringLookupFactory.INSTANCE.interpolatorStringLookup(lookupMap, null, false); 759 * 760 * new StringSubstitutor(variableResolver).replace("... ${dns:address|apache.org} ..."); 761 * </pre> 762 * <p> 763 * The above examples convert {@code "address|apache.org"} to the IP address of {@code apache.org}. 764 * </p> 765 * 766 * @return the DnsStringLookup singleton instance. 767 * @since 1.8 768 */ 769 public StringLookup dnsStringLookup() { 770 return DnsStringLookup.INSTANCE; 771 } 772 773 /** 774 * Returns the EnvironmentVariableStringLookup singleton instance where the lookup key is an environment variable 775 * name. 776 * <p> 777 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 778 * </p> 779 * 780 * <pre> 781 * StringLookupFactory.INSTANCE.environmentVariableStringLookup().lookup("USER"); 782 * </pre> 783 * <p> 784 * Using a {@link StringSubstitutor}: 785 * </p> 786 * 787 * <pre> 788 * StringSubstitutor.createInterpolator().replace("... ${env:USER} ...")); 789 * </pre> 790 * <p> 791 * The above examples convert (on Linux) {@code "USER"} to the current user name. On Windows 10, you would use 792 * {@code "USERNAME"} to the same effect. 793 * </p> 794 * 795 * @return The EnvironmentVariableStringLookup singleton instance. 796 */ 797 public StringLookup environmentVariableStringLookup() { 798 return StringLookupFactory.INSTANCE_ENVIRONMENT_VARIABLES; 799 } 800 801 /** 802 * Returns the FileStringLookup singleton instance. 803 * <p> 804 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 805 * </p> 806 * 807 * <pre> 808 * StringLookupFactory.INSTANCE.fileStringLookup().lookup("UTF-8:com/domain/document.properties"); 809 * </pre> 810 * <p> 811 * Using a {@link StringSubstitutor}: 812 * </p> 813 * 814 * <pre> 815 * StringSubstitutor.createInterpolator().replace("... ${file:UTF-8:com/domain/document.properties} ...")); 816 * </pre> 817 * <p> 818 * The above examples convert {@code "UTF-8:com/domain/document.properties"} to the contents of the file. 819 * </p> 820 * 821 * @return The FileStringLookup singleton instance. 822 * @since 1.5 823 */ 824 public StringLookup fileStringLookup() { 825 return FileStringLookup.INSTANCE; 826 } 827 828 /** 829 * Returns a new function-based lookup where the request for a lookup is answered by applying the function with a 830 * lookup key. 831 * 832 * @param <R> the function return type. 833 * @param function the function. 834 * @return a new MapStringLookup. 835 * @since 1.9 836 */ 837 public <R> StringLookup functionStringLookup(final Function<String, R> function) { 838 return FunctionStringLookup.on(function); 839 } 840 841 /** 842 * Returns a {@link InterpolatorStringLookup} containing the configured 843 * {@link #addDefaultStringLookups(Map) default lookups}. See the class documentation for 844 * details on how these defaults are configured. 845 * <p> 846 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 847 * </p> 848 * 849 * <pre> 850 * StringLookupFactory.INSTANCE.interpolatorStringLookup().lookup("${sys:os.name}, ${env:USER}"); 851 * </pre> 852 * <p> 853 * Using a {@link StringSubstitutor}: 854 * </p> 855 * 856 * <pre> 857 * StringSubstitutor.createInterpolator().replace("... ${sys:os.name}, ${env:USER} ...")); 858 * </pre> 859 * <p> 860 * The above examples convert {@code "${sys:os.name}, ${env:USER}"} to the OS name and Linux user name. 861 * </p> 862 * 863 * @return the default {@link InterpolatorStringLookup}. 864 */ 865 public StringLookup interpolatorStringLookup() { 866 return InterpolatorStringLookup.INSTANCE; 867 } 868 869 /** 870 * Returns a new InterpolatorStringLookup. If {@code addDefaultLookups} is {@code true}, the configured 871 * {@link #addDefaultStringLookups(Map) default lookups} are included in addition to the ones 872 * provided in {@code stringLookupMap}. (See the class documentation for details on how default lookups 873 * are configured.) 874 * 875 * @param stringLookupMap the map of string lookups. 876 * @param defaultStringLookup the default string lookup; this lookup is used when a variable cannot be 877 * resolved using the lookups in {@code stringLookupMap} or the configured default lookups (if enabled) 878 * @param addDefaultLookups whether to use default lookups as described above. 879 * @return a new InterpolatorStringLookup. 880 * @since 1.4 881 */ 882 public StringLookup interpolatorStringLookup(final Map<String, StringLookup> stringLookupMap, 883 final StringLookup defaultStringLookup, final boolean addDefaultLookups) { 884 return new InterpolatorStringLookup(stringLookupMap, defaultStringLookup, addDefaultLookups); 885 } 886 887 /** 888 * Returns a new InterpolatorStringLookup using the given key-value pairs and the configured 889 * {@link #addDefaultStringLookups(Map) default lookups} to resolve variables. (See the class 890 * documentation for details on how default lookups are configured.) 891 * 892 * @param <V> the value type the default string lookup's map. 893 * @param map the default map for string lookups. 894 * @return a new InterpolatorStringLookup. 895 */ 896 public <V> StringLookup interpolatorStringLookup(final Map<String, V> map) { 897 return new InterpolatorStringLookup(map); 898 } 899 900 /** 901 * Returns a new InterpolatorStringLookup using the given lookup and the configured 902 * {@link #addDefaultStringLookups(Map) default lookups} to resolve variables. (See the class 903 * documentation for details on how default lookups are configured.) 904 * 905 * @param defaultStringLookup the default string lookup. 906 * @return a new InterpolatorStringLookup. 907 */ 908 public StringLookup interpolatorStringLookup(final StringLookup defaultStringLookup) { 909 return new InterpolatorStringLookup(defaultStringLookup); 910 } 911 912 /** 913 * Returns the JavaPlatformStringLookup singleton instance. Looks up keys related to Java: Java version, JRE 914 * version, VM version, and so on. 915 * <p> 916 * The lookup keys with examples are: 917 * </p> 918 * <ul> 919 * <li><b>version</b>: "Java version 1.8.0_181"</li> 920 * <li><b>runtime</b>: "Java(TM) SE Runtime Environment (build 1.8.0_181-b13) from Oracle Corporation"</li> 921 * <li><b>vm</b>: "Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)"</li> 922 * <li><b>os</b>: "Windows 10 10.0, architecture: amd64-64"</li> 923 * <li><b>hardware</b>: "processors: 4, architecture: amd64-64, instruction sets: amd64"</li> 924 * <li><b>locale</b>: "default locale: en_US, platform encoding: iso-8859-1"</li> 925 * </ul> 926 * 927 * <p> 928 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 929 * </p> 930 * 931 * <pre> 932 * StringLookupFactory.INSTANCE.javaPlatformStringLookup().lookup("version"); 933 * </pre> 934 * <p> 935 * Using a {@link StringSubstitutor}: 936 * </p> 937 * 938 * <pre> 939 * StringSubstitutor.createInterpolator().replace("... ${java:version} ...")); 940 * </pre> 941 * <p> 942 * The above examples convert {@code "version"} to the current VM version, for example, 943 * {@code "Java version 1.8.0_181"}. 944 * </p> 945 * 946 * @return The JavaPlatformStringLookup singleton instance. 947 */ 948 public StringLookup javaPlatformStringLookup() { 949 return JavaPlatformStringLookup.INSTANCE; 950 } 951 952 /** 953 * Returns the LocalHostStringLookup singleton instance where the lookup key is one of: 954 * <ul> 955 * <li><b>name</b>: for the local host name, for example {@code EXAMPLE}.</li> 956 * <li><b>canonical-name</b>: for the local canonical host name, for example {@code EXAMPLE.apache.org}.</li> 957 * <li><b>address</b>: for the local host address, for example {@code 192.168.56.1}.</li> 958 * </ul> 959 * 960 * <p> 961 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 962 * </p> 963 * 964 * <pre> 965 * StringLookupFactory.INSTANCE.localHostStringLookup().lookup("canonical-name"); 966 * </pre> 967 * <p> 968 * Using a {@link StringSubstitutor}: 969 * </p> 970 * 971 * <pre> 972 * StringSubstitutor.createInterpolator().replace("... ${localhost:canonical-name} ...")); 973 * </pre> 974 * <p> 975 * The above examples convert {@code "canonical-name"} to the current host name, for example, 976 * {@code "EXAMPLE.apache.org"}. 977 * </p> 978 * 979 * @return The DateStringLookup singleton instance. 980 */ 981 public StringLookup localHostStringLookup() { 982 return LocalHostStringLookup.INSTANCE; 983 } 984 985 /** 986 * Returns a new map-based lookup where the request for a lookup is answered with the value for that key. 987 * 988 * @param <V> the map value type. 989 * @param map the map. 990 * @return a new MapStringLookup. 991 */ 992 public <V> StringLookup mapStringLookup(final Map<String, V> map) { 993 return FunctionStringLookup.on(map); 994 } 995 996 /** 997 * Returns the NullStringLookup singleton instance which always returns null. 998 * 999 * @return The NullStringLookup singleton instance. 1000 */ 1001 public StringLookup nullStringLookup() { 1002 return StringLookupFactory.INSTANCE_NULL; 1003 } 1004 1005 /** 1006 * Returns the PropertiesStringLookup singleton instance. 1007 * <p> 1008 * Looks up the value for the key in the format "DocumentPath::MyKey". 1009 * </p> 1010 * <p> 1011 * Note the use of "::" instead of ":" to allow for "C:" drive letters in paths. 1012 * </p> 1013 * <p> 1014 * For example: "com/domain/document.properties::MyKey". 1015 * </p> 1016 * 1017 * <p> 1018 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1019 * </p> 1020 * 1021 * <pre> 1022 * StringLookupFactory.INSTANCE.propertiesStringLookup().lookup("com/domain/document.properties::MyKey"); 1023 * </pre> 1024 * <p> 1025 * Using a {@link StringSubstitutor}: 1026 * </p> 1027 * 1028 * <pre> 1029 * StringSubstitutor.createInterpolator().replace("... ${properties:com/domain/document.properties::MyKey} ...")); 1030 * </pre> 1031 * <p> 1032 * The above examples convert {@code "com/domain/document.properties::MyKey"} to the key value in the properties 1033 * file at the path "com/domain/document.properties". 1034 * </p> 1035 * 1036 * @return The PropertiesStringLookup singleton instance. 1037 * @since 1.5 1038 */ 1039 public StringLookup propertiesStringLookup() { 1040 return PropertiesStringLookup.INSTANCE; 1041 } 1042 1043 /** 1044 * Returns the ResourceBundleStringLookup singleton instance. 1045 * <p> 1046 * Looks up the value for a given key in the format "BundleName:BundleKey". 1047 * </p> 1048 * <p> 1049 * For example: "com.domain.messages:MyKey". 1050 * </p> 1051 * <p> 1052 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1053 * </p> 1054 * 1055 * <pre> 1056 * StringLookupFactory.INSTANCE.resourceBundleStringLookup().lookup("com.domain.messages:MyKey"); 1057 * </pre> 1058 * <p> 1059 * Using a {@link StringSubstitutor}: 1060 * </p> 1061 * 1062 * <pre> 1063 * StringSubstitutor.createInterpolator().replace("... ${resourceBundle:com.domain.messages:MyKey} ...")); 1064 * </pre> 1065 * <p> 1066 * The above examples convert {@code "com.domain.messages:MyKey"} to the key value in the resource bundle at 1067 * {@code "com.domain.messages"}. 1068 * </p> 1069 * 1070 * @return The ResourceBundleStringLookup singleton instance. 1071 */ 1072 public StringLookup resourceBundleStringLookup() { 1073 return ResourceBundleStringLookup.INSTANCE; 1074 } 1075 1076 /** 1077 * Returns a ResourceBundleStringLookup instance for the given bundle name. 1078 * <p> 1079 * Looks up the value for a given key in the format "MyKey". 1080 * </p> 1081 * <p> 1082 * For example: "MyKey". 1083 * </p> 1084 * <p> 1085 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1086 * </p> 1087 * 1088 * <pre> 1089 * StringLookupFactory.INSTANCE.resourceBundleStringLookup("com.domain.messages").lookup("MyKey"); 1090 * </pre> 1091 * <p> 1092 * The above example converts {@code "MyKey"} to the key value in the resource bundle at 1093 * {@code "com.domain.messages"}. 1094 * </p> 1095 * 1096 * @param bundleName Only lookup in this bundle. 1097 * @return a ResourceBundleStringLookup instance for the given bundle name. 1098 * @since 1.5 1099 */ 1100 public StringLookup resourceBundleStringLookup(final String bundleName) { 1101 return new ResourceBundleStringLookup(bundleName); 1102 } 1103 1104 /** 1105 * Returns the ScriptStringLookup singleton instance. NOTE: This lookup is not included 1106 * as a {@link #addDefaultStringLookups(Map) default lookup} unless explicitly enabled. See 1107 * the class level documentation for details. 1108 * <p> 1109 * Looks up the value for the key in the format "ScriptEngineName:Script". 1110 * </p> 1111 * <p> 1112 * For example: "javascript:3 + 4". 1113 * </p> 1114 * <p> 1115 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1116 * </p> 1117 * 1118 * <pre> 1119 * StringLookupFactory.INSTANCE.scriptStringLookup().lookup("javascript:3 + 4"); 1120 * </pre> 1121 * <p> 1122 * When used through a {@link StringSubstitutor}, this lookup must either be added programmatically 1123 * (as below) or enabled as a default lookup using the {@value #DEFAULT_STRING_LOOKUPS_PROPERTY} system property 1124 * (see class documentation). 1125 * </p> 1126 * 1127 * <pre> 1128 * Map<String, StringLookup> lookupMap = new HashMap<>(); 1129 * lookupMap.put("script", StringLookupFactory.INSTANCE.scriptStringLookup()); 1130 * 1131 * StringLookup variableResolver = StringLookupFactory.INSTANCE.interpolatorStringLookup(lookupMap, null, false); 1132 * 1133 * String value = new StringSubstitutor(variableResolver).replace("${script:javascript:3 + 4}"); 1134 * </pre> 1135 * <p> 1136 * The above examples convert {@code "javascript:3 + 4"} to {@code "7"}. 1137 * </p> 1138 * 1139 * @return The ScriptStringLookup singleton instance. 1140 * @since 1.5 1141 */ 1142 public StringLookup scriptStringLookup() { 1143 return ScriptStringLookup.INSTANCE; 1144 } 1145 1146 /** 1147 * Returns the SystemPropertyStringLookup singleton instance where the lookup key is a system property name. 1148 * 1149 * <p> 1150 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1151 * </p> 1152 * 1153 * <pre> 1154 * StringLookupFactory.INSTANCE.systemPropertyStringLookup().lookup("os.name"); 1155 * </pre> 1156 * <p> 1157 * Using a {@link StringSubstitutor}: 1158 * </p> 1159 * 1160 * <pre> 1161 * StringSubstitutor.createInterpolator().replace("... ${sys:os.name} ...")); 1162 * </pre> 1163 * <p> 1164 * The above examples convert {@code "os.name"} to the operating system name. 1165 * </p> 1166 * 1167 * @return The SystemPropertyStringLookup singleton instance. 1168 */ 1169 public StringLookup systemPropertyStringLookup() { 1170 return StringLookupFactory.INSTANCE_SYSTEM_PROPERTIES; 1171 } 1172 1173 /** 1174 * Returns the UrlDecoderStringLookup singleton instance. 1175 * <p> 1176 * Decodes URL Strings using the UTF-8 encoding. 1177 * </p> 1178 * <p> 1179 * For example: "Hello%20World%21" becomes "Hello World!". 1180 * </p> 1181 * <p> 1182 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1183 * </p> 1184 * 1185 * <pre> 1186 * StringLookupFactory.INSTANCE.urlDecoderStringLookup().lookup("Hello%20World%21"); 1187 * </pre> 1188 * <p> 1189 * Using a {@link StringSubstitutor}: 1190 * </p> 1191 * 1192 * <pre> 1193 * StringSubstitutor.createInterpolator().replace("... ${urlDecoder:Hello%20World%21} ...")); 1194 * </pre> 1195 * <p> 1196 * The above examples convert {@code "Hello%20World%21"} to {@code "Hello World!"}. 1197 * </p> 1198 * 1199 * @return The UrlStringLookup singleton instance. 1200 * @since 1.6 1201 */ 1202 public StringLookup urlDecoderStringLookup() { 1203 return UrlDecoderStringLookup.INSTANCE; 1204 } 1205 1206 /** 1207 * Returns the UrlDecoderStringLookup singleton instance. 1208 * <p> 1209 * Decodes URL Strings using the UTF-8 encoding. 1210 * </p> 1211 * <p> 1212 * For example: "Hello World!" becomes "Hello+World%21". 1213 * </p> 1214 * <p> 1215 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1216 * </p> 1217 * 1218 * <pre> 1219 * StringLookupFactory.INSTANCE.urlEncoderStringLookup().lookup("Hello World!"); 1220 * </pre> 1221 * <p> 1222 * Using a {@link StringSubstitutor}: 1223 * </p> 1224 * 1225 * <pre> 1226 * StringSubstitutor.createInterpolator().replace("... ${urlEncoder:Hello World!} ...")); 1227 * </pre> 1228 * <p> 1229 * The above examples convert {@code "Hello World!"} to {@code "Hello%20World%21"}. 1230 * </p> 1231 * 1232 * @return The UrlStringLookup singleton instance. 1233 * @since 1.6 1234 */ 1235 public StringLookup urlEncoderStringLookup() { 1236 return UrlEncoderStringLookup.INSTANCE; 1237 } 1238 1239 /** 1240 * Returns the UrlStringLookup singleton instance. This lookup is not included 1241 * as a {@link #addDefaultStringLookups(Map) default lookup} unless explicitly enabled. See 1242 * the class level documentation for details. 1243 * <p> 1244 * Looks up the value for the key in the format "CharsetName:URL". 1245 * </p> 1246 * <p> 1247 * For example, using the HTTP scheme: "UTF-8:http://www.google.com" 1248 * </p> 1249 * <p> 1250 * For example, using the file scheme: 1251 * "UTF-8:file:///C:/somehome/commons/commons-text/src/test/resources/document.properties" 1252 * </p> 1253 * <p> 1254 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1255 * </p> 1256 * 1257 * <pre> 1258 * StringLookupFactory.INSTANCE.urlStringLookup().lookup("UTF-8:https://www.apache.org"); 1259 * </pre> 1260 * <p> 1261 * When used through a {@link StringSubstitutor}, this lookup must either be added programmatically 1262 * (as below) or enabled as a default lookup using the {@value #DEFAULT_STRING_LOOKUPS_PROPERTY} system property 1263 * (see class documentation). 1264 * </p> 1265 * 1266 * <pre> 1267 * Map<String, StringLookup> lookupMap = new HashMap<>(); 1268 * lookupMap.put("url", StringLookupFactory.INSTANCE.urlStringLookup()); 1269 * 1270 * StringLookup variableResolver = StringLookupFactory.INSTANCE.interpolatorStringLookup(lookupMap, null, false); 1271 * 1272 * String value = new StringSubstitutor(variableResolver).replace("${url:UTF-8:https://www.apache.org}"); 1273 * </pre> 1274 * <p> 1275 * The above examples convert {@code "UTF-8:https://www.apache.org"} to the contents of that page. 1276 * </p> 1277 * 1278 * @return The UrlStringLookup singleton instance. 1279 * @since 1.5 1280 */ 1281 public StringLookup urlStringLookup() { 1282 return UrlStringLookup.INSTANCE; 1283 } 1284 1285 /** 1286 * Returns the XmlStringLookup singleton instance. 1287 * <p> 1288 * Looks up the value for the key in the format "DocumentPath:XPath". 1289 * </p> 1290 * <p> 1291 * For example: "com/domain/document.xml:/path/to/node". 1292 * </p> 1293 * <p> 1294 * Using a {@link StringLookup} from the {@link StringLookupFactory}: 1295 * </p> 1296 * 1297 * <pre> 1298 * StringLookupFactory.INSTANCE.xmlStringLookup().lookup("com/domain/document.xml:/path/to/node"); 1299 * </pre> 1300 * <p> 1301 * Using a {@link StringSubstitutor}: 1302 * </p> 1303 * 1304 * <pre> 1305 * StringSubstitutor.createInterpolator().replace("... ${xml:com/domain/document.xml:/path/to/node} ...")); 1306 * </pre> 1307 * <p> 1308 * The above examples convert {@code "com/domain/document.xml:/path/to/node"} to the value of the XPath in the XML 1309 * document. 1310 * </p> 1311 * 1312 * @return The XmlStringLookup singleton instance. 1313 * @since 1.5 1314 */ 1315 public StringLookup xmlStringLookup() { 1316 return XmlStringLookup.INSTANCE; 1317 } 1318}