Почему я не получаю пробелов между значениями текстовых узлов? - PullRequest
0 голосов
/ 30 ноября 2018

Я использую выражение Xpath для получения текстовых узлов из документа XML, как показано ниже:

<company>
    <emp>
        <dept>Acct</dept>
        <salary>1000</salary>
        <proj>
            <under>E01</under>
             <under>E02</under>
        </proj>
        <name>John Doe</name>
        <gender>male</gender>
    </emp>
</company>

Я написал следующее выражение XPATH для получения текстовых значений:

normalize-space(string(//emp))

Он извлекает правильные значения и вывод выглядит следующим образом:

Acct1000E01E02John Doemale

Обратите внимание , что между значениями текстовых узлов из разных узлов нет пробелов.

Я на самом деле хочу , чтобы выходное значение было таким:

`Acct 1000 E01 E02 John Doe`

Я использовал javax.xml.xpath для анализа и построения дерева следующим образом:

DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
 Document document = builder.parse(new File("/employees.xml"));

 XPath xpath = XPathFactory.newInstance().newXPath();
 String expression = "normalize-space(string(//emp))";
 String output= (String)xPath.compile(expression).evaluate(document, XPathConstants.STRING);

Я использую JAVA SE 10 здесь.Итак, версия Xpath - 1.0

Есть ли лучший способ извлечь текстовые значения?Я довольно новичок в XPath, поэтому любые предложения будут полезны.

Ответы [ 2 ]

0 голосов
/ 01 декабря 2018

О, дорогой, это сложно ...

Прежде всего, вы не отметили свой вопрос версией XPath.Обычно люди, которые не знают о версиях XPath, используют древнюю версию 1.0, поэтому я сделаю это предположение: извините, если это не так.

В XPath 1.0 - функция, которой присваивается набор узлов икоторая ожидает, что строка использует строковое значение первого узла в наборе узлов, взятое в порядке документа.

В вашем запросе

normalize-space(string(//emp))

//emp выбирает набор узлов,который содержит один узел, поэтому string () принимает строковое значение этого узла.Строковое значение узла элемента является объединением всех его потомков текстового узла.Функция normalize-space удаляет начальные и конечные пробелы и нормализует внутреннее пространство до одного символа пробела.

Вы показали ваш XML в отступной форме как

<company>
    <emp>
        <dept>Acct</dept>
        <salary>1000</salary>

и т. Д., Так что это разумноожидать, что пробел между элементами образует часть строкового значения элемента <emp>.Но вы не сказали нам, как документ был проанализирован и превращен в дерево узлов.Парсеры часто предоставляют несколько вариантов того, как это сделать, в частности, как обрабатывать пробелы между узлами элементов.Большинство сохраняют пробелы по умолчанию, если, возможно, не существует схемы или DTD, которые сообщают анализатору, что пробелы незначительны.Известно, что синтаксический анализатор MSXML от Microsoft удаляет пробелы по умолчанию, что создает значительные проблемы при использовании XML для представления описательных документов, но на самом деле облегчает жизнь людям, использующим XML для такого рода недокументированных данных.

Ваш синтаксический анализатор по тем или иным причинам (мы не можем сказать), похоже, удалил пробел между узлами элемента.Ни один запрос XPath не вернет его снова.У вас могут быть варианты при создании документа для сохранения пробела;это зависит от инструментов, которые вы используете.

Ваш второй вопрос касается удаления одного из элементов ввода.Это выходит за рамки XPath.XPath может только выбирать узлы из входных данных, но никак не может их изменять.Чтобы изменить дерево, вам нужен XSLT или XQuery.

Ваша попытка решить проблему с //emp[not(descendant::gender)] безнадежно обречена, потому что это будет выбирать только тех сотрудников, у которых нет элемента-потомка с именем gender.Похоже, вы угадываете семантику, а не используете спецификацию или учебное пособие.

0 голосов
/ 30 ноября 2018

Вы почти правы здесь.Выбор оператора not - правильный путь.Это должно быть примерно так:

/html/body/company/emp/*[not(self::gender)]

То есть все дочерние узлы emp, кроме gender узла.
Здесь приведен полный пример в javascript:

let xpathExpression = '/html/body/company/emp/*[not(self::gender)]';
let contextNode = window.document;
let xpathResult = document.evaluate(xpathExpression, contextNode, 
                                        null, XPathResult.ANY_TYPE, null);

console.log(xpathResult.iterateNext());
console.log(xpathResult.iterateNext());
console.log(xpathResult.iterateNext());
console.log(xpathResult.iterateNext());
...