У меня есть исходный документ XHTML с элементами в нескольких пространствах имен, которые я преобразовываю в HTML-документ (очевидно, без пространств имен). В моих XSL-шаблонах я сопоставляю только элементы пространства имен XHTML, чтобы удалить элементы, не совместимые с HTML, из дерева результатов. Однако на выходе, в то время как эти элементы исчезли, пробелы, которые я использовал для их отступов, остаются, т. Е. Строк нерелевантных CR / LF и вкладок.
Например, если это мой ввод:
<div id="container"> <svg:svg> <svg:foreignObject> <img /> </svg:foreignObject> </svg:svg> </div>
После применения преобразования это будет выход:
<div id="container"> <img /> </div>
Хотя мой желаемый результат:
<div id="container"> <img /> </div>
Это происходит с использованием TransforMiiX (прикрепление таблицы стилей локально в Firefox) и libxslt (прикрепление таблицы стилей к серверу с PHP), поэтому я знаю, что это, вероятно, результат того, что некоторый параметр XSL не устанавливается, но я попытался сыграть с <xsl:output indent="yes|no" />
, xml:space="default|preserve"
, <xsl:strip-space elements="foo bar|*" />
, все безрезультатно.
Это будет реализовано на стороне сервера, поэтому, если нет способа сделать это в необработанном XSL, но есть способ сделать это в PHP, я соглашусь с этим.
Я знаю, что это не проблема пространства имен, так как я получаю тот же результат, если я удаляю ЛЮБОЙ элемент.
Белое пространство, которое вы видите, находится в исходном документе. Стандарты по умолчанию XSLT говорят, что текстовые узлы должны быть скопированы, неважно, пусты ли они или нет. Чтобы переопределить правило по умолчанию, включите:
<xsl:template match="text()" />
Альтернативно: <xsl:apply-templates select="node()" />
<xsl:apply-templates />
(или <xsl:apply-templates select="node()" />
) и явно укажите, к каким дочерним элементам вы хотите применить шаблоны. Этот метод может потребоваться, если ваше преобразование частично зависит от шаблона идентификации (в этом случае пустой шаблон для текстовых узлов будет контрпродуктивным).
Я выделил «незначительное» белое пространство в вашем фрагменте, как Word это сделает:
<div id="container">¶ ····<svg:svg>¶ ········<svg:foreignObject>¶ ············<img />¶ ········</svg:foreignObject>¶ ····</svg:svg>¶ </div>
EDIT: вы также можете изменить шаблон своей личности следующим образом:
<xsl:template match="node() | @*"> <xsl:copy> <!-- select everything except blank text nodes --> <xsl:apply-templates select=" node()[not(self::text())] | text()[normalize-space() != ''] | @* " /> </xsl:copy> </xsl:template>
Это удалит пустой текстовый узел (значения атрибута остаются нетронутыми, они не являются текстовыми узлами). Используйте <xsl:output indent="yes" />
чтобы печатать результат.
У вас есть два пути для достижения желаемого результата: либо вы исправляете свое первоначальное преобразование, чтобы обрабатывать пустоты по-разному, либо сохраняете свою трансформацию как есть, и добавляете второй проход, чтобы префикс вывода. Если ваше первоначальное преобразование осложнено, я бы рекомендовал использовать 2-проходный подход. Вы не хотите, чтобы ваше преобразование было еще более сложным, или вы создадите некоторые угловые случаи, когда вы не получите желаемых результатов, и вам придется добавить более специальную обработку дела и потенциально добавить ошибки к чему-то, что раньше работало , и т.д…
Вы должны иметь возможность игнорировать узлы пробелов, тестируя их с помощью normalize-text()
. Вот как мог бы выглядеть второй проход. Если вы пойдете с 1-проходным подходом, код будет примерно таким же, как я предполагаю.
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes" /> <xsl:template match="text()"> <xsl:if test="normalize-space(.) != ''"> <xsl:value-of select="."/> </xsl:if> </xsl:template> <xsl:template match="node()"> <xsl:copy> <xsl:copy-of select="@*" /> <xsl:apply-templates /> </xsl:copy> </xsl:template> </xsl:stylesheet>