document.evaluate JavaScript ничего не возвращает в AppleScript

#javascript #xpath #applescript

#javascript #xpath #applescript

Вопрос:

Я пишу скрипт AppleScript для очистки веб-страницы в Safari, и есть часть, с которой я уже давно борюсь.

Это возвращает требуемый текст: log (do JavaScript "document.querySelector('h1 > span').innerHTML;" in front document)

И это не: log (do JavaScript "document.evaluate('//h1/span/text()[normalize-space()]', document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" in front document)

В инспекторе браузера работают оба подхода, но в AppleScript ни один вариант xpaths не сработал для меня.

И мне действительно нужно использовать document.evaluate функцию, чтобы делать что-то вроде document.evaluate("//p[contains(., 'Metrics')]/following-sibling::p[1]/text()[normalize-space()]", document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; того же скрипта.

Как это нужно переписать, чтобы начать выдавать результаты в AppleScript?


Пример HTML-кода:

 <html>
<body>
  <h1>
    <span>Test Entry</span>
  </h1>
</body>
</html>
 

Вывод веб-инспектора Safari (демонстрирует, что оба querySelector и evaluate работают без проблем):

 > document.querySelector('h1 > span').innerHTML;
< "Test Entry"
> document.evaluate('//h1/span/text()[normalize-space()]', document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
< "Test Entry"
 

Код редактора AppleScript:

 tell application "Safari"
  log (do JavaScript "document.querySelector('h1 > span').innerHTML;" in front document)
  log (do JavaScript "document.evaluate('//h1/span/text()[normalize-space()]', document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" in front document)
end tell
 

Вывод редактора AppleScript (демонстрирует, что querySelector работает, а evaluate не работает):

 (*Test Entry*)
(**)
 

Комментарии:

1. And this doesn’t — что он возвращает?

2. Ничего. Он также не вызывает никаких ошибок, и я не уверен, как проверить, куда он попадает. Просто ни один вариант xpath, который я пробовал, не сработал. 🙁

3. Можете ли вы воспроизвести это поведение с минимальным источником ввода, которым вы могли бы поделиться?

4. Да, теперь я обновил сообщение минимальным образцом HTML и вывел код, созданный в Safari Web Inspector (где код работает) и Script Editor (где document.evaluate ничего не возвращает). Спасибо, что спросили.

5. @Vladimir, я написал ответ с высказанными предложениями. Что касается вашего другого примера, я бы предложил проверить, работает ли log (do JavaScript "document.querySelector('h1 > span');" in front document) log (do JavaScript "document.querySelector('h1 > span').firstChild;" in front document) он так же хорошо или нет (**) .

Ответ №1:

Выражение XPath, которое вы используете для своей минимальной выборки ( //h1/span/text()[normalize-space()] ), выбирает текстовый узел в DOM браузера и с помощью document.evaluate('//h1/span/text()[normalize-space()]', document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue вашего кода Javascript возвращает этот текстовый узел (https://dom.spec.whatwg.org/#text ). Хотя специализированный инспектор браузера может затем напрямую отображать содержимое текстового узла, похоже, что ваша консоль AppleScript этого не делает.

Если вы хотите, чтобы ваш код Javascript возвращал простую строку со значением текстового узла, вы можете использовать data свойство (https://dom.spec.whatwg.org/#dom-characterdata-data ) текстового узла, подобно тому, как вы использовали innerHTML свойство узла элемента, которое вы получили от querySelector вызова.

Итак

 document.evaluate('//h1/span/text()[normalize-space()]', document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue
 

в Javascript возвращает текстовый узел DOM, и чтобы получить строку с содержимым текстового узла, используйте data свойство с, например

 document.evaluate('//h1/span/text()[normalize-space()]', document.body, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.data
 

Другой вариант — использовать

 document.evaluate('//h1/span/text()[normalize-space()]', document.body, null, XPathResult.STRING_TYPE, null).stringValue
 

Поскольку вам нужен минимальный пример, обратите также внимание, что, пока вы используете абсолютный XPath, начинающийся с / или // , вы ничего не получаете, используя document.body в качестве второго аргумента document.evaluate , document достаточно также передать один и дать тот же результат.