Проблема с разрывом строки XSLT

#xml #xslt

#xml #xslt

Вопрос:

Я пытаюсь создать html-вывод в соответствии с полями в xml-файле с помощью xslt. И я называю их в соответствии с отношением grandparent-parent-child-grandchild в xml

Например:

 <root>
  <node1>
      <node2>
         <node3>Data</node3>
      </node2>
  </node1>
  

Что мне нужно, так это создать, скажем, текстовое поле с именем node1__node2__node3
Что я делал до сих пор, так это

 <input type="text" name="node1__
        node2__
        node3__"
  

Но то, что я хочу, это:

 <input type="text" name="node1__node2__node3__"/>
  

Так что это бесполезно. Мой xslt для создания этого бесполезного вывода:

 <xsl:template name="chooseNameID">
    <xsl:param name="currentNode"/><!-- in this case currentNode is node3 -->
    <xsl:variable name="fieldNames">
        <xsl:for-each select="$currentNode/ancestor::*">
                <xsl:value-of select="name(.)"/>__
        </xsl:for-each>
    </xsl:variable>

    <xsl:attribute name="name">
        <xsl:value-of select="$fieldNames"/>                            
    </xsl:attribute>

</xsl:template>
  

Я предполагаю, что проблема в <xsl:value-of , но я не могу найти никакого решения для этого.

Спасибо

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

1. Хороший вопрос, 1. Смотрите мой ответ для полного, короткого и простого решения. 🙂

Ответ №1:

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

 <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="node3">
    <xsl:variable name="vName">
     <xsl:for-each select=
      "ancestor-or-self::*[not(position()=last())]">
        <xsl:value-of select="name()"/>
        <xsl:if test="not(position()=last())">__</xsl:if>
     </xsl:for-each>
    </xsl:variable>

    <input type="text" name="{$vName}"/>
 </xsl:template>
</xsl:stylesheet>
  

при применении к предоставленному XML-документу:

 <root>
    <node1>
        <node2>
            <node3>Data</node3>
        </node2>
    </node1>
</root>
  

выдает желаемый, правильный результат:

 <input type="text" name="node1__node2__node3"/>
  

Обратите внимание: использование AVT (шаблон значения атрибута) для генерации требуемого вывода в одной короткой строке.

Ответ №2:

Нежелательные пробелы, включая новые строки, являются частью литерала текстового узла в цикле.

В документе таблицы стилей текстовые узлы, содержащие только пробелы, игнорируются за исключением внутри xsl:text . Однако пробелы, расположенные рядом с другим текстом, являются частью этого текста.

Буквенными пробелами в таблице стилей можно управлять с помощью xsl:text .

     <!-- change this -->
    <xsl:for-each select="$currentNode/ancestor::*">
        <xsl:value-of select="name(.)"/>__
    </xsl:for-each>

    <!-- to this -->
    <xsl:for-each select="$currentNode/ancestor::*">
        <xsl:value-of select="name(.)"/>__<xsl:text/>
    </xsl:for-each>

    <!-- or this -->
    <xsl:for-each select="$currentNode/ancestor::*">
        <xsl:value-of select="name(.)"/>
        <xsl:text>__</xsl:text>
    </xsl:for-each>
  

Ответ №3:

Как обычно, задав вопрос, вы находите решение.

Изменение <xsl:value-of select="$fieldNames"/> строки с помощью этого <xsl:value-of select="normalize-space($fieldNames)" сработало для меня.

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

1. В результате все равно останутся пробелы, поскольку normalize-space() заменит каждую внутреннюю последовательность пробелов одним пробелом.