Выбор дочернего текстового узла среди пустых текстовых узлов в сложном элементе XML с использованием XPath - PullRequest
1 голос
/ 09 августа 2010

Я ломал голову над этим, но, похоже, не могу понять это правильно, и я не подбираю правильные ключевые слова в Google ..

Я недавно начал играть с XSLT и XPath, чтобы создать XML-описание глоссариев на естественном языке - для моего проекта.

Проблема в том, что я решил использовать сложные элементы «смешанный контент» для некоторых слов, а в некоторых случаях хочу получить только текстовый узел.

Вот часть документа XML:

...
<entry category="substantiv">
  <word lang="sv">semester</word>
  <word lang="de">
    <article>der</article>Urlaub
    <plural>Urlaube</plural>
  </word>
</entry>
...

В моем документе много элементов entry, и в этом случае я хочу получить Urlaub, используя: /entry/word[@lang='de']/text(), что из-за моих разрывов строк не сработает. Я обнаружил, что на самом деле есть три текстовых узла .. .../text()[2], конечно, будет работать .. Однако я заранее не знаю, где будут разрывы строк или сколько. Если xml отформатирован, как показано ниже, моя первая версия пути будет работать, но не вторая:

...
<word lang="de"><article>der</article>Urlaub
  <plural>Urlaube</plural>
</word>
...

То, что я хочу сделать, это выделить все непосредственные текстовые узлы слова [@ lang = 'de'], а затем удалить ненужные пробелы, используя normalize-space(). Тем не менее, как мне сделать это с помощью XPath? Или есть лучший способ? Кажется, это было бы легко, но я не могу понять это. Кстати, я пытаюсь сделать это в документе XSLT.

normalize-space(/entry/word[@lang='de']/text()[*]) - это одна из вещей, которые я пробовал, но, похоже, это делает что-то другое.

/ Благодарен за любую помощь.

Обновление:

Вот часть XSLT согласно запросу:

...
<xsl:choose>
    <xsl:when test="@category='substantiv'">
        <em><xsl:value-of select="word[@lang='de']/article" /></em>
        <xsl:value-of select="normalize-space(word[@lang='de']/text()[2])" />
        <em>pl. <xsl:value-of select="word[@lang='de']/plural" /></em>
    </xsl:when>
...

Этот код прекрасно работает с первой версией форматирования. Чтобы прояснить, что я хочу сделать, это получить значение текстового узла в сложном элементе <word lang="de">, несмотря на то, что оно может быть отформатировано с помощью разрывов строк и пробелов. То, что я буду делать со значением, зависит от контекста, но сейчас я просто помещу его в документ в формате xhtml.

Update2: Сейчас я использую <xsl:strip-space elements="*"/>, что устраняет проблему наличия пустых текстовых узлов. Я также использую:

...
<xsl:choose>
  <xsl:when test="@category='substantiv'">
    <em><xsl:value-of select="word[@lang='de']/article" /></em>
    <xsl:text> </xsl:text>
    <xsl:value-of select="normalize-space(word[@lang='de']/text())" />
    <xsl:text>, </xsl:text>
    <em>pl. <xsl:value-of select="word[@lang='de']/plural" /></em>
  </xsl:when>
...

Тем не менее придется нормализовать, так как пробел все еще добавляется после "Urlaub" в XML.

Когда мне нужно добраться до текстового узла «Urlaub» за пределами используемого документа XSLT:
<xsl:value-of select="normalize-space(word[@lang='de']/text()[normalize-space() != ''])" />

Спасибо всем за помощь, ребята!

Обновление 3: Пытался улучшить заголовок

Ответы [ 4 ]

2 голосов
/ 10 августа 2010

Это преобразование:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/">
  <xsl:value-of select="/*/entry/word[@lang='de']/text()[1]"/>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному XML-документу (в верхнем элементе dict):

<dict>
    <entry category="substantiv">
        <word lang="sv">semester</word>
        <word lang="de">
            <article>der</article>Urlaub
            <plural>Urlaube</plural>
        </word>
    </entry>
</dict>

дает в точности нужный результат :

Urlaub

Do note : использование инструкции <xsl:strip-space> для удаления всех текстовых узлов, содержащих только пробелы, из исходного XMLdocument.

Следовательно, дополнительная обработка (normalize-space () и т. д.) не требуется .

0 голосов
/ 09 августа 2010

Попробуйте:

/entry/word[@lang='de']/child::text()[normalize-space(.) != '']

Значение, захватить все дочерние текстовые узлы, но не те, которые нормализуются в пустую строку.

-Oisin

0 голосов
/ 10 августа 2010

Я думаю, что это скелет того, что вы хотите, за исключением любого normalize-space (), чтобы все выглядело именно так, как вы хотите.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="/">
    <xsl:apply-templates select=".//word"/>
  </xsl:template>
  <xsl:template match="word">
    <xsl:apply-templates select=".//text()"/>
  </xsl:template>
  <xsl:template match="text()"><xsl:value-of select="."/><xsl:text> </xsl:text></xsl:template>  
</xsl:stylesheet>

Ключ - .//text(), который возвращаетобъединение ВСЕХ дочерних текстовых узлов на любом уровне вложенности ниже узла контекста ().

0 голосов
/ 09 августа 2010

Теперь, когда я вижу ваш код, я рекомендую следующее:

<xsl:choose>
  <xsl:when test="@category='substantiv'">
    <em><xsl:value-of select="word[@lang='de']/article" /></em>^
    <!-- select the first non-empty text node and normalize it -->
    <xsl:value-of select="normalize-space(word[@lang='de']/text()[normalize-space() != ''][1])" />
    <em>pl. <xsl:value-of select="word[@lang='de']/plural" /></em>
  </xsl:when>

Оригинальная версия ответа

Для начала:

<entry category="substantiv">
  <word lang="sv">semester</word>
  <word lang="de">
    <article>der</article>Urlaub
    <plural>Urlaube</plural>
  </word>
</entry>

При прохождении через этот XSLT 1.0:

<!-- identity template copies everything 1:1, unless other templates apply -->
<xsl:template match="*|@*">
  <xsl:copy>
    <xsl:apply-templates select="*|@*" />
  </xsl:copy>
</xsl:template>

<!-- empty template: ignore every white-space-only text-node child of <word> -->
<xsl:template match="word/text()[normalize-space() = '']" />

выдаст следующее:

<entry category="substantiv">
  <word lang="sv">semester</word>
  <word lang="de"><article>der</article>Urlaub<plural>Urlaube</plural></word>
</entry>

Этот ответ является предположением и может не совпадать с вашим.Ваш вопрос нуждается в разъяснении в любом случае.Не всегда это то, что вы думаете вы хотите так же, как вы на самом деле хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...