Перейти к содержимому

Фотография

Кавычки в XPath (HOWTO)


  • Авторизуйтесь для ответа в теме
Сообщений в теме: 2

#1 vitorg

vitorg

    Опытный участник

  • Members
  • PipPipPipPip
  • 408 сообщений

Отправлено 14 апреля 2009 - 11:01

Всем привет!

Вот предположим, что есть у нас такой XPath-локатор:

xpath=//td[text()='my simple string']

Всё вроде бы просто - ищет ячейку таблицы в которой есть текст: my simple string. Но что делать если текст, который надо найти содержит одинарные кавычки, вот такой: my 'apos' string? Не беда, можно обрамить его в двойные кавычки в XPath-локаторе вот так:

xpath=//td[text()="my 'apos' string"]

Всё прекрасно работает. Аналогично если текст содержит двойные кавычки, то обрамляем в одинарные.
Но что делать если текст содержит как одинарные так и двойные кавычки, например: my 'apos' and "quot" string? Первая мысль - от'escape'ить их обратным слешем, вот так:

xpath=//td[text()='my \'apos\' and "quot" string']

И тут мы обнаруживаем, что escape'инг в XPath не работает :( К сожалению это не только в Selenium'е так, так во всём XPath'е.
Как быть?
Можно использовать такое решение:

xpath=//td[text()=concat('my ',"'",'apos',"'",' and "quot" string')]

Т.е. мы всегда используем одинарные кавычки для обрамления, кроме самих одинарных кавычек, которые обрамляем двойными, а потом "склеиваем" строку. Теперь всё прекрасно работает.

Можно написать такой вот escape-метод для подобных случаев (Java):
/**
	 * Escapes the characters in a passed string to be suitable to pass to an XPath expression.
	 * <p/>
	 * Because there is no escape character in XPath string values, this method is not really escapes passed string, but
	 * transforms it using a little trick with XPath concatenation function.
	 * <p/>
	 * Algorithm is: <ol><li>If string is <code>null</code>, then <code>null</code> is returns.</li><li>If string
	 * doesn't contains "'" (apostrophe) character, then it returns as is, but quotes with "'" (apostrophe) character.
	 * For example: <code>abcd</code> string will be returned as <code>'abcd'</code>.</li><li>If string contains "'"
	 * (apostrophe) character, then it splits into string tokens and replaces with XPath <code>concat()</code> function.
	 * For example: <code>ab'cd'ef</code> string will be returned as <code>concat('ab',"'",'cd',"'",'ef')</code></li><ol>
	 *
	 * @param string String to escape.
	 * @return Escaped string.
	 */
	@Nullable
	public static String escapeXPath(@Nullable String string) {
		if (string == null) {
			return null;
		} else if (string.contains("'")) {
			StringBuilder sb = new StringBuilder();
			sb.append("concat('");

			for (int i = 0; i < string.length(); i++) {
				char ch = string.charAt(i);
				if ('\'' == ch) {
					sb.append("',\"").append(ch).append("\",'");
				} else {
					sb.append(ch);
				}
			}

			sb.append("')");
			return sb.toString();
		} else {
			return "'" + string + "'";
		}
	}

Конструктивная критика приветствуется :)
  • 3

#2 dlg99

dlg99

    Специалист

  • Members
  • PipPipPipPipPip
  • 609 сообщений
  • ФИО:Andrey Yegorov
  • Город:Redmond, WA

Отправлено 15 апреля 2009 - 16:21

C# - использовал примерно такое решение.
делает то же самое - concat() из строки.

// if we need to do xpath like //a[text()=<string>] and <string> contains both apostrophes and quotes
// the only way to properly pass the string is to use concat()
private static string QuoteXPathAttributeString(string s)
{
	return s.Contains("'")
				   ? "concat('" + String.Replace("'", "',\"'\",'") + "')"
				   : "'" + s + "'";
}

  • 0
Andrey Yegorov. Изображение

#3 crider

crider

    Новый участник

  • Members
  • Pip
  • 1 сообщений
  • ФИО:Василий Иванович Рогов

Отправлено 14 июня 2017 - 21:39


Можно использовать такое решение:

xpath=//td[text()=concat('my ',"'",'apos',"'",' and "quot" string')]

Т.е. мы всегда используем одинарные кавычки для обрамления, кроме самих одинарных кавычек, которые обрамляем двойными, а потом "склеиваем" строку. Теперь всё прекрасно работает.

Можно написать такой вот escape-метод для подобных случаев (Java):
/**
	 * Escapes the characters in a passed string to be suitable to pass to an XPath expression.
	 * <p/>
	 * Because there is no escape character in XPath string values, this method is not really escapes passed string, but
	 * transforms it using a little trick with XPath concatenation function.
	 * <p/>
	 * Algorithm is: <ol><li>If string is <code>null</code>, then <code>null</code> is returns.</li><li>If string
	 * doesn't contains "'" (apostrophe) character, then it returns as is, but quotes with "'" (apostrophe) character.
	 * For example: <code>abcd</code> string will be returned as <code>'abcd'</code>.</li><li>If string contains "'"
	 * (apostrophe) character, then it splits into string tokens and replaces with XPath <code>concat()</code> function.
	 * For example: <code>ab'cd'ef</code> string will be returned as <code>concat('ab',"'",'cd',"'",'ef')</code></li><ol>
	 *
	 * @param string String to escape.
	 * @return Escaped string.
	 */
	@Nullable
	public static String escapeXPath(@Nullable String string) {
		if (string == null) {
			return null;
		} else if (string.contains("'")) {
			StringBuilder sb = new StringBuilder();
			sb.append("concat('");

			for (int i = 0; i < string.length(); i++) {
				char ch = string.charAt(i);
				if ('\'' == ch) {
					sb.append("',\"").append(ch).append("\",'");
				} else {
					sb.append(ch);
				}
			}

			sb.append("')");
			return sb.toString();
		} else {
			return "'" + string + "'";
		}
	}
Конструктивная критика приветствуется :)

 

 

Чувак, спасибо - поперло... А то весь вечер сижу кавычку экранирую... начал подозревать, что с экранированием в xpath что-то не так.


  • 0


Количество пользователей, читающих эту тему: 0

0 пользователей, 0 гостей, 0 анонимных