Я пытаюсь выбрать узлы, которые не содержат текст. Этот бит php-кода пропускает пустой узел в примере xml. Тем не менее, когда я пытаюсь онлайн-тестер (как http://freeformatter.com/xpath-tester.html) это не имеет никаких проблем.
Это вещь PHP?
Мой php код:
$path = "//RecipeSteps/RecipeStep[not(text())]";
$stepsQuery = $this->xpath->query($path);
$numResults = $stepsQuery->length;
Мой образец xml:
<?xml version="1.0" encoding="utf-8"?>
<Recipes>
<RecipeSteps>
<RecipeStep number="1">Dummy content</RecipeStep>
<RecipeStep number="2">Dummy content</RecipeStep>
<RecipeStep number="3">Dummy content</RecipeStep>
<RecipeStep number="4">Dummy content</RecipeStep>
<RecipeStep number="5">Dummy content</RecipeStep>
<RecipeStep number="6"></RecipeStep>
<RecipeStep number="7">Variations</RecipeStep>
<RecipeStep number="8">Some variation content..</RecipeStep>
</RecipeSteps>
</Recipes>
Если вы ищете решение XPATH, используйте //RecipeSteps/(RecipeStep[string-length() = 0])
,
например
$path = "//RecipeSteps/(RecipeStep[string-length() = 0])";
$stepsQuery = $this->xpath->query($path);
$numResults = $stepsQuery->length;
При выборе полного пути это работает:
$xmlString = '<?xml version="1.0" encoding="utf-8"?>
<Recipes>
<RecipeSteps>
<RecipeStep number="1">Dummy content</RecipeStep>
<RecipeStep number="2">Dummy content</RecipeStep>
<RecipeStep number="3">Dummy content</RecipeStep>
<RecipeStep number="4">Dummy content</RecipeStep>
<RecipeStep number="5">Dummy content</RecipeStep>
<RecipeStep number="6"></RecipeStep>
<RecipeStep number="7">Variations</RecipeStep>
<RecipeStep number="8">Some variation content..</RecipeStep>
</RecipeSteps>
</Recipes>';
$dom = new DOMDocument();
$dom->loadXML($xmlString);
$xpath = new DOMXpath($dom);
# it works also well: //RecipeSteps/RecipeStep[not(text())]
$query = $xpath->query('//Recipes/RecipeSteps/RecipeStep[not(text())]');
//returns "6"print 'RecipeStep number: ' . $query->item(0)->getAttribute('number');
Также выбираем//RecipeSteps/RecipeStep[not(text())]
«работает как шарм также хорошо. Так что, скорее всего, вы делаете что-то не так.
Выражения пути //RecipeStep[not(text())]
а также //RecipeStep[string-length() = 0]
не имеют в виду то же самое, но принимая в качестве входных данных документ, который вы показали, они возвращают точно так же. В обоих случаях один RecipeStep
узел выбран в результате:
<RecipeStep number="6"/>
//RecipeStep[not(text())]
означает на простом английском:
Выберите узлы элемента, называемые
RecipeStep
в любом месте документа, но только если у них нет непосредственных дочерних текстовых узлов.
С другой стороны, //RecipeStep[string-length() = 0]
средства
Выберите узлы элемента, называемые
RecipeStep
в любом месте документа, но только в том случае, если длина их строкового значения (объединение всех текстовых узлов-потомков) равна 0.
Разница будет очевидна только в том случае, если шаг рецепта № 6 действительно будет выглядеть
<RecipeStep number="6"><child>text</child></RecipeStep>
Затем, //RecipeStep[not(text())]
все равно выбрал бы этот узел, тогда как //RecipeStep[string-length() = 0]
не вернул бы ничего.
(И просто чтобы прояснить: ведущий //RecipeSteps
то, что я опустил, ничего не меняет.)
Итак, ваше исходное выражение XPath правильное — и принятый ответ делает то же самое, что и исходный. XPath здесь не виноват.