From 1522d77bfccc8284b95d691c0d35aaa88bc23d5e Mon Sep 17 00:00:00 2001 From: ChrisJoosse Date: Tue, 7 Oct 2025 14:59:18 -0700 Subject: [PATCH] backport Locator.xq fix --- src/org/labkey/test/Locator.java | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/org/labkey/test/Locator.java b/src/org/labkey/test/Locator.java index 8bcf8b532a..89d772df63 100644 --- a/src/org/labkey/test/Locator.java +++ b/src/org/labkey/test/Locator.java @@ -985,10 +985,39 @@ public static XPathLocator pageHeader(String headerText) * Direct port from attibuteValue function in selenium IDE locatorBuilders.js * @param value to be quoted * @return value with either ' or " around it or assembled from parts + * @implNote {@link Quotes#escape(String)} doesn't handle trailing quotes correctly */ public static String xq(String value) { - return Quotes.escape(value); + if (!value.contains("'")) { + return "'" + value + "'"; + } else if (!value.contains("\"")) { + return '"' + value + '"'; + } else { + StringBuilder result = new StringBuilder("concat("); + while (true) { + int apos = value.indexOf("'"); + int quot = value.indexOf('"'); + if (apos < 0) { + result.append("'").append(value).append("'"); + break; + } else if (quot < 0) { + result.append('"').append(value).append('"'); + break; + } else if (quot < apos) { + String part = value.substring(0, apos); + result.append("'").append(part).append("'"); + value = value.substring(part.length()); + } else { + String part = value.substring(0, quot); + result.append('"').append(part).append('"'); + value = value.substring(part.length()); + } + result.append(','); + } + result.append(')'); + return result.toString(); + } } /**