Обрезать пробелы только из родительского элемента
Я хотел бы обрезать начальные пробелы внутри тегов p в XML, так что это:
<p> Hey, <em>italics</em> and <em>italics</em>!</p>
Становится так:
<p>Hey, <em>italics</em> and <em>italics</em>!</p>
(Обрезка концевых пробелов не повредит, но это не обязательно.)
Теперь я знаю normalize-whitespace()
должен сделать это, но если я попытаюсь применить его к текстовым узлам..
<xsl:template match="text()">
<xsl:text>[</xsl:text>
<xsl:value-of select="normalize-space(.)"/>
<xsl:text>]</xsl:text>
</xsl:template>
... он применяется к каждому текстовому узлу (в скобках) индивидуально и высасывает их всухую:
[Hey,]<em>[italics]</em>[and]<em>[italics]</em>[!]
Мой XSLT выглядит в основном так:
<xsl:template match="p">
<xsl:apply-templates/>
</xsl:template>
Так есть ли какой-нибудь способ, которым я могу позволить завершить apply-templates и затем запустить normalize-space на выходе, что должно сделать правильную вещь?
3 ответа
Эта таблица стилей:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p//text()[1][generate-id()=
generate-id(ancestor::p[1]
/descendant::text()[1])]">
<xsl:variable name="vFirstNotSpace"
select="substring(normalize-space(),1,1)"/>
<xsl:value-of select="concat($vFirstNotSpace,
substring-after(.,$vFirstNotSpace))"/>
</xsl:template>
</xsl:stylesheet>
Выход:
<p>Hey, <em>italics</em> and <em>italics</em>!</p>
Редактировать 2: лучшее выражение (теперь только три вызова функций).
Редактировать 3: Соответствие первого потомка текстового узла (не только первый узел, если это текстовый узел). Благодаря комментарию @Dimitre.
Теперь с этим входом:
<p><b> Hey, </b><em>italics</em> and <em>italics</em>!</p>
Выход:
<p><b>Hey, </b><em>italics</em> and <em>italics</em>!</p>
Я бы сделал что-то вроде этого:
<xsl:template match="p">
<xsl:apply-templates/>
</xsl:template>
<!-- strip leading whitespace -->
<xsl:template match="p/node()[1][self::text()]">
<xsl:call-template name="left-trim">
<xsl:with-param name="s" value="."/>
</xsl:call-template>
</xsl:template>
Это уберет левое пространство от начального узла потомка <p>
элемент, если это текстовый узел. Он не будет убирать пространство из первого дочернего узла текста, если это не первый дочерний узел. Например в
<p><em>Hey</em> there</p>
Я намеренно стараюсь не убирать пространство с передней части "там", потому что это заставит слова работать вместе при рендеринге в браузере. Если вы хотите удалить это пространство, измените шаблон соответствия на
match="p/text()[1]"
Если вы также хотите удалить конечные пробелы, как, возможно, подразумевает ваш заголовок, добавьте эти два шаблона:
<!-- strip trailing whitespace -->
<xsl:template match="p/node()[last()][self::text()]">
<xsl:call-template name="right-trim">
<xsl:with-param name="s" value="."/>
</xsl:call-template>
</xsl:template>
<!-- strip leading/trailing whitespace on sole text node -->
<xsl:template match="p/node()[position() = 1 and
position() = last()][self::text()]"
priority="2">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
Определения шаблонов обрезки слева и справа находятся в шаблоне обрезки для XSLT (не проверено). Они могут быть медленными для документов с большим количеством <p>
s. Если вы можете использовать XSLT 2.0, вы можете заменить шаблоны вызовов на
<xsl:value-of select="replace(.,'^\s+','')" />
а также
<xsl:value-of select="replace(.,'\s+$','')" />
(Спасибо Присцилле Уолмсли.)
Вы хотите:
<xsl:template match="text()">
<xsl:value-of select=
"substring(
substring(normalize-space(concat('[',.,']')),2),
1,
string-length(.)
)"/>
</xsl:template>
Это оборачивает строку в "[]"
затем выполняет normalize-string()
, а затем, наконец, удаляет символы переноса.