2015-09-23 3 views
2

Я построить текстовую строку, которая сцепляет весь текст, найденный в коллекции файлов XML, с помощью:XSLT: Конкатенация текста в коллекции XML файла

<xsl:variable name="text-accumulated"> 
     <xsl:for-each select="collection($collection-string)"> 
       <xsl:copy-of select="//concat(text()[1], ' ')"/> 
     </xsl:for-each> 
</xsl:variable> 

Примечания: concat'ing пространства предотвращено слова из слияние вокруг некоторых возвратов каретки (или перевода строк).

Результат

Это работает для меня. Но я всегда опасаюсь использовать //.

Я также знаю, что результаты глубокой копии, сделанные copy-of, могут иногда вас удивить. Я использовал value-of и получил одинаковые результаты.

Есть ли лучший способ объединить весь текст в коллекцию файлов?

Существует ли встроенная функция, которую я должен использовать вместо (IRT, Saxon 9.5)?

Есть value-of лучший вариант, чем copy-of?

+0

Does ' 'не хватает ? Что касается глубоких копий, вы хотите вообще создать какие-либо узлы? Похоже, вы просто хотите получить строковое значение. –

+0

Мартин, это не приносит желаемого результата, но я буду работать над ним - это, безусловно, более сжатый код. Хороший намек на копию: это может привести к ошибочному узлу(), значение-нет. – Paulb

+0

Ваш 'select =" // concat (text() [1], '') "' на 'xsl: copy-of' в любом случае вычисляет строки, и этот способ скорее будет работать как' xsl: sequence'. Это может помочь, если вы разместите три или четыре фрагмента примеров документов, в которых вы хотите объединить текст или строковое значение, плюс желаемый результат, тогда нам легче сказать, чего вы хотите достичь, и предложить альтернативы. '// concat (text() [1], '')' выглядит необычно для меня, что я не уверен, что вы хотите вычислить с ним, не видя некоторых образцов. –

ответ

0

<xsl:copy-of select="//concat(text()[1], ' ')"/>

Эта инструкция фактически не копирует полный текст из документа XML!

Вот пример:

<a> 
    <b>X1<c>Y</c>X2</b> 
</a> 

Когда вышеуказанный документ XML, обрабатывается с помощью следующего преобразования (который включает в себя только инструкции XSLT из предоставленного кода):

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="text"/> 

    <xsl:template match="/"> 
    <xsl:copy-of select="//concat(text()[1], ' ')"/> 
    </xsl:template> 
</xsl:stylesheet> 

результатом является :

X1 Y 

Как мы видим, строка "X2" не Прес nt на выходе.

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

Другими словами, полученный результат не является точно конкатенацией текстовых узлов XML-документов.

В случае, если вы не связаны с последней проблемой, один правильный XPath 2.0 выражения, которая соединяет все текстовые узлы в документе, используя пространство, как разделитель:

//string-join(text(), ' ') 

С этой коррекцией, ваш код при условии, становится:

<xsl:variable name="text-accumulated"> 
     <xsl:for-each select="collection($collection-string)"> 
       <xsl:copy-of select="//string-join(text(), ' ')"/> 
     </xsl:for-each> 
</xsl:variable> 

ли value-of лучший вариант, чем copy-of?

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

<xsl:value-of> 

производит единый текстовый узел которого строковое значение есть конкатенация строковых значений выбранных элементов (возможно, разделенных сепаратором-строки, если указан атрибут separator.

С другой стороны ,

<xsl:copy-of> 

производит копию последовательности узлов и/или атомарных значений, с каждым новым узлом, содержащего копию всех детей, атрибуты и (по умолчанию) пространства имен исходного узла, рекурсивно.

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

Это работает для меня. Но я всегда осторожен с использованием //

можно использовать шаблоны вместо абсолютных выражений. В вашем случае что-то вроде этого:

<xsl:variable name="text-accumulated"> 
    <xsl:apply-templates select="collection($collection-string)" mode="mergeText"/> 
</xsl:variable> 

    <xsl:template match="text()" mode="mergeText"> 
    <xsl:value-of select="concat(., ' ')"/> 
    </xsl:template> 
+0

Выдающийся и образовательный ответ .. спасибо. Незначительный каламбур в вашем первом вопросе относительно «не поймать всех» - с моим XML. В любом случае, ваш ответ был отличным. И подсказка к Мартину Х для его замечательных комментариев. – Paulb

+0

@Paulb, Добро пожаловать. Вы можете найти этот учебный курс Pluralsight, который охватывает как XPath 2.0, так и XSLT 2.0: http://www.pluralsight.com/courses/xslt-foundations-part1 –

Смежные вопросы