Игнорирование пустого пространства при использовании substring-after в xsl - PullRequest
1 голос
/ 29 сентября 2010

У меня есть следующий xml.

<root query="Smith Antony Blah Jones">

И следующий xsl для разделения строки на разные переменные.

<xsl:variable name="query">
<xsl:value-of select="substring-before (root/@query, ' ')" />
</xsl:variable>

<xsl:variable name="query1">
<xsl:value-of select="substring-before(substring-after(root/@query, ' '), ' ')" />
</xsl:variable>

<xsl:variable name="query2"><xsl:value-of select="substring-before(substring-after(root/@query, $query1), ' ')"/></xsl:variable>

<xsl:template match="root">
<search data="{$query}" data1="{$query1}" data2="{$query2}" "/>

Однако я получаю следующий html

<search data="Smith" data1="Antony" data2="" data3=""/>

Я вижу, что xsl смотрит на первый пробел между 'Antony' и 'Blah' и ничего не возвращает как таковойчто после «Антония» и до «Бла».Как я могу пропустить первый пробел и захватить «Бла»?

Я использую XSLT 1.0, BTW.

Спасибо!

Ответы [ 5 ]

3 голосов
/ 29 сентября 2010

Давайте пройдемся по вашим шагам, потому что совершенно ясно, что происходит и как это исправить.

Вы начинаете со следующей строки: "Smith Antony Blah Jones"

Затем вы присваиваете переменнуюquery результат substring-before в первой строке.Это присваивает "Smith" query.

Затем вы присваиваете query2 значение substring-before substring-after вашей исходной строки.substring-after возвращает "Antony Blah Jones", а substring-before возвращает "Antony".Пока все хорошо.

Теперь ваше следующее назначение ищет "Antony" в исходной строке, но затем полученная строка будет " Blah Jones", поэтому, когда вы запускаете substring-before, вы соответствуете самому первому пробелу.

Существует множество возможных решений.Очевидным будет вызов substring-after перед вызовом substring-before, например:

<xsl:value-of 
  select="substring-before(substring-after(substring-after(root/@query, $query1), ' '),' ')"
/>

Но это довольно уродливо.В качестве альтернативы вы можете использовать substring или просто добавить пробел к "Antony" при первом вызове substring-after.

Я думаю, что вам лучше определить рекурсивный шаблон для получения следующего токена, а затемпередать оставшуюся строку себеЭто позволит вам получить произвольное количество разделенных пробелами токенов из строки без необходимости иметь так много пронумерованных переменных.Примерно так:

<xsl:template name="recursive-tokenizer">
  <xsl:param name="input"/>
  <xsl:choose>
    <!-- Test whether the input token contains a space. -->
    <xsl:when test="contains($input,' ')">
      <!-- Output a token. -->
      <xsl:value-of select="substring-before($input,' ')"/>

      <!-- Call this template with the rest of the string. -->
      <xsl:call-template name="recursive-tokenizer">
        <xsl:with-param name="input" select="substring-after($input,' ')"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <!-- There is no space, so just output the input. -->
      <xsl:value-of select="$input"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
0 голосов
/ 30 сентября 2010

Если вы используете XSLT 2, вы можете сделать это следующим образом:

<search>
  <xsl:for-each select="tokenize(/root/@query,'\s+')">
    <xsl:attribute name="data{(position() - 1)[. &gt; 0]}"
                   select="."/>
  </xsl:for-each>
</search>
0 голосов
/ 30 сентября 2010

На самом деле вы спрашиваете: «Как я могу использовать XSLT для анализа строки?» Хотя можно сделать (рекурсивный подход, предложенный Алехандро, является хорошим), зачастую гораздо проще предварительно обработать такой документ, проанализировать строки с использованием языков, которые лучше обрабатывают строки, чем XSLT, и изменить документ перед его преобразованием.

Например, в C # вы можете написать простой метод, подобный этому:

foreach (XmlElement elm in doc.SelectNodes("//*[@query]"))
{
   foreach (string s in elm.GetAttribute("@query")
      .Split(new[] {' '})
      .Where(x => !(string.IsNullOrEmpty(x))))
   {
      XmlElement query = doc.CreateElement("query")
      query.InnerText = s;
      elm.AppendChild(query);
   }
}

Теперь ваши элементы будут выглядеть так:

<root query="Antony Blah Smith Jones">
   <query>Antony</query>
   <query>Blah</query>
   <query>Smith</query>
   <query>Jones</query>
</root>

и доступ к этим элементам подстроки в XSLT тривиален.

0 голосов
/ 29 сентября 2010

Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="root">
        <search>
            <xsl:call-template name="query"/>
        </search>
    </xsl:template>
    <xsl:template name="query">
        <xsl:param name="pString" select="@query"/>
        <xsl:param name="pNumber" select="0"/>
        <xsl:param name="pTop" select="3"/>
        <xsl:choose>
            <xsl:when test="$pNumber > $pTop"/>
            <xsl:when test="contains($pString,' ')">
                <xsl:call-template name="query">
                    <xsl:with-param name="pString" 
                                    select="substring-before($pString,' ')"/>
                    <xsl:with-param name="pNumber" select="$pNumber"/>
                    <xsl:with-param name="pTop" select="$pTop"/>
                </xsl:call-template>
                <xsl:call-template name="query">
                    <xsl:with-param name="pString" 
                                    select="substring-after($pString,' ')"/>
                    <xsl:with-param name="pNumber" select="$pNumber + 1"/>
                    <xsl:with-param name="pTop" select="$pTop"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:attribute 
                     name="data{substring($pNumber, 1 div ($pNumber != 0))}">
                    <xsl:value-of select="$pString"/>
                </xsl:attribute>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

С этим входом:

<root query="Smith Antony Blah Jones"/>

Выход:

<search data="Smith" data1="Antony" data2="Blah" data3="Jones" />
0 голосов
/ 29 сентября 2010

Можете ли вы просто изменить эту строку:

<xsl:variable name="query2"><xsl:value-of select="substring-before(substring-after(root/@query, $query1), ' ')"/></xsl:variable>

на эту:

<xsl:variable name="query2"><xsl:value-of select="substring-before(concat(substring-after(root/@query, $query1),' '), ' ')"/></xsl:variable>

Просто добавив пробел в конец $query1Не самый чистый, но я думаю, что это будет работать ...

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