XSLT: убрать дубликаты br-тегов из бегущего текста - PullRequest
2 голосов
/ 03 ноября 2010

При редактировании форматированного текста наша CMS генерирует XML-файлы с дубликатами <br/>-тегов.Я хотел бы удалить их, чтобы генерировать выходные данные, которые могут быть прочитаны другим приложением, которое не оценивает возникновение этих дубликатов.

Пример ввода:

<p>
   Lorem ipsum...<br />
   <br />
   ..dolor sit
</p>

Сгенерирует что-то вроде этого:

<p>
   Lorem ipsum...<br />
   ..dolor sit
</p>

Я уже использую XSLT для манипулирования выводом другими способами, и нашелнекоторые примеры регулярных выражений и PHP, которые делают то же самое, я просто думаю, что было бы лучше, если бы я мог сделать это с XSLT из-за скорости двигателя в нашей CMS (Roxen).

Заранее спасибо!

Ответы [ 2 ]

4 голосов
/ 03 ноября 2010

Опираясь на ответ @ Nic, вы можете использовать

<xsl:template match='br[preceding-sibling::node()[1][self::br]]'/>

Я только что изменил * на node().Это решило бы проблему объединения двух <br/> с текстом между ними.Однако он перестанет удалять дубликаты <br/> s, даже если между ними будет только пробельный узел.

Чтобы решить это ...

Устаревший

Сначала я предположил, что вы можете убрать узлы только для пробелов из p элементов во входном документе, поместив это на верхний уровень вашего XSLT:

<xsl:strip-space  elements="p"/>

Но @Alejandro указал, что это может легко привести к потере важных пробелов , как в <p><em>bar</em> <em>baz</em></p>.

Так что вместо этого

используйте этот измененный шаблон соответствия:

<xsl:template match='br[preceding-sibling::node()
                        [not(self::text() and normalize-space(.) = "")][1]
                        [self::br]]'/>

Вроде некрасиво, но должно работать.Это будет соответствовать и подавлять «любой br, для которого предыдущий узел-брат, который не является текстовым узлом только для пробелов, также является br».: -)

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

<xsl:template match="br">
   <xsl:if test="not(preceding-sibling::node()
                        [not(self::text() and normalize-space(.) = '')][1]
                        [self::br])">
      <xsl:copy>
          <xsl:apply-templates select="@*|node()" />
      </xsl:copy>
   </xsl:if>
</xsl:template>

Здесь мы используем копию преобразования идентичности, когда <br /> не тот, который мы хотим подавить.Я не думаю, что <br /> может принимать дочерние элементы или текст, но это не помешает быть безопасным.

( Обновил выше. Я забыл закончить этот пример кодав последний раз я сохранял правки.)

3 голосов
/ 03 ноября 2010

Используя преобразование идентичности, чтобы оставить все остальное в покое, вы можете просто подавить каждое <br/>, которому непосредственно предшествует другое.Очевидно, что вы можете просто вставить шаблон в существующий XSLT.

<xsl:template match='node()|@*'>
    <xsl:copy>
        <xsl:apply-templates select='node()|@*'/>
    </xsl:copy>
</xsl:template>

<xsl:template match='br[(preceding-sibling::*)[1][self::br]]'/>

Пустой шаблон просто подавит это <br/>.

Обновление: как указывает @LarsH, этот шаблонслишком либерален в своем сопоставлении и, вероятно, должен выглядеть примерно так:

<xsl:template match='br[preceding-sibling::node()[1]
    [not(self::text() and normalize-space(.) = "")][self::br]]'/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...