четверг, 7 апреля 2016 г.

Об XML-фильтрах OpenOffice. Часть 3-я.

  1. Решение проблемы разделения на строки.
  2. Демонстрация работы подсветки синтаксиса кода

Решение проблемы разделения на строки.



Коль скоро мы начали с определения цвета, возьмемся за раскрашивание текста. То есть целью будет получение текста документа, раскрашенного с помощью BB-кодов. Добавим в преобразование следующую функцию, которая будет оборачивать переданный узел тегами COLOR
Код xml Выделить

<xsl:function name="my:colorize">

  <xsl:param name="node"/>

  <xsl:variable name="color" select="my:style-property-value($node, 'fo:color')"/>

  <xsl:value-of select="concat('[COLOR=&quot;', $color, '&quot;]', $node, '[/COLOR]')"/>

</xsl:function>

Кроме того, нам понадобится шаблон, обрабатывающий текстовые узлы, а так же отредактируем шаблон, с которого начинается обработка документа
Код xml Выделить

<xsl:template match="/">

  <root>

    <xsl:text disable-output-escaping="yes">

      &lt;![CDATA[

    </xsl:text>

    <xsl:apply-templates select="//office:body"/>  

    <xsl:text disable-output-escaping="yes">

      ]]&gt;

    </xsl:text>

  </root>

</xsl:template>

<xsl:template match="text()">

  <xsl:value-of select="my:colorize(.)" disable-output-escaping="yes"/>

</xsl:template>

 

<xsl:template match="office:binary-data"/>

Кроме того добавил <xsl:template match="office:binary-data"/>, чтобы исключить бинарные данные из выходного потока.

Вот результат
Код xml Выделить

<?xml version="1.0" encoding="UTF-8"?>

<root>

<![CDATA[

[COLOR="#2e74b5"]Заголовок 1[/COLOR]Обычный текст[COLOR="#2e74b5"]Заголовок 2[/COLOR][COLOR="#1f4d78"]Заголовок 3[/COLOR][COLOR="#2e74b5"]Заголовок 4[/COLOR][COLOR="#2e74b5"]Заголовок 5[/COLOR][COLOR="#1f4d78"]Заголовок 6[/COLOR][COLOR="#1f4d78"]Заголовок 7[/COLOR]Название[COLOR="#5a5a5a"]Подзаголовок[/COLOR][COLOR="#5b9bd5"]Сильное выделение[/COLOR]Строгий[COLOR="#404040"]Цитата 2[/COLOR][COLOR="#5a5a5a"]Слабая ссылка[/COLOR][COLOR="#5b9bd5"]Сильная ссылка[/COLOR]Название книгиАбзац списка.ЖирныйКурисивПодчеркнутыйПеречекнутыйХНижний индексХВерхний идексКрупный шрифт 72Мелкий шрифт 8Левое выравниваниеВыравнивание по центруПравое выравниваниеПервый пункт маркированного спискаВторой пункт маркированного спискаПервый пункт нумерованного спискаПункт 1.a;alfjasdf; lj l ;l lj ;lk lkj;lkj l sdls dfslkj as;lПункт 1.b b xj 'nj pf [eqyz&amp;Второй пункт нумерованного списка[COLOR="#ff0000"]Текст красного цвета[/COLOR][COLOR="#00b0f0"]Текст синего цвета[/COLOR]Выделение желтым/*Далее таблица*/1.11.21.31.41.22.22.32.43.13.23.33.4[COLOR="#0563c1"]Ссылка на гуголь[/COLOR]/*Далее картинка*/ЗакладкаТекст с отступом 2 смСсылка на сноску1Сноска на странице.

]]>

</root>

 

Если текстовые данные просто вставить в пост как цитату, получится вот что
Цитата:
Заголовок 1Обычный текстЗаголовок 2Заголовок 3Заголовок 4Заголовок 5Заголовок 6Заголовок 7НазваниеПодзаголовокСильное выделениеСтрогийЦитата 2Слабая ссылкаСильная ссылкаНазвание книгиАбзац списка.ЖирныйКурисивПодчеркнутыйПеречекнутыйХНижний индексХВерхний идексКрупный шрифт 72Мелкий шрифт 8Левое выравниваниеВыравнивание по центруПравое выравниваниеПервый пункт маркированного спискаВторой пункт маркированного спискаПервый пункт нумерованного спискаПункт 1.a;alfjasdf; lj l ;l lj ;lk lkj;lkj l sdls dfslkj as;lПункт 1.b b xj 'nj pf [eqyz&amp;Второй пункт нумерованного спискаТекст красного цветаТекст синего цветаВыделение желтым/*Далее таблица*/1.11.21.31.41.22.22.32.43.13.23.33.4Ссылка на гуголь/*Далее картинка*/ЗакладкаТекст с отступом 2 смСсылка на сноску1Сноска на странице.
Приятно, конечно, что все раскрасилось как в оригинальном документе, но там вроде как текст многострочным был. А это еще что такое? Так здесь еще строки отрезаются по ширине страницы, а в коде все вообще в одну строку сложено.

Если взглянуть на фрагменты кода с текстом, которые мы уже рассмотрели ранее, то можно заметить, что среди форматирующих элементов (тех, которые имеют ссылку на стиль) на верхнем уровне оказывается либо text:p (для обычного текста) либо text:h (для заголовков). Нетрудно догадаться, что назначение этих элементов примерно такое же, как у элементов p и h1-h6 в HTML. То есть иными словами, мы видим, что любой текст "упакован" в блочный элемент, внутри которого дополнительно могут находиться инлайновые форматирующие элементы. Конечно, это несколько упрощенный взгляд, но если принять во внимание только это обстоятельство, можно получить гораздо более адекватный результат.
Добавим в преобразование такой шаблон
Код xml Выделить

<xsl:template match="text:h|text:p">

  <xsl:apply-templates/>

  <xsl:text>

  </xsl:text>

</xsl:template>

И получим куда более удовлетворительный результат.
Кликните здесь для просмотра всего текста
Цитата:
Заголовок 1
Обычный текст
Заголовок 2
Заголовок 3
Заголовок 4

Заголовок 5
Заголовок 6
Заголовок 7
Название
Подзаголовок
Сильное выделение
Строгий
Цитата 2
Слабая ссылка
Сильная ссылка

Название книги
Абзац списка.
Жирный
Курисив
Подчеркнутый
Перечекнутый
ХНижний индекс
ХВерхний идекс
Крупный шрифт 72
Мелкий шрифт 8
Левое выравнивание
Выравнивание по центру
Правое выравнивание
Первый пункт маркированного списка
Второй пункт маркированного списка

Первый пункт нумерованного списка
Пункт 1.a;alfjasdf; lj l ;l lj ;lk lkj;lkj l sdls dfslkj as;l
Пункт 1.b b xj 'nj pf [eqyz&amp;
Второй пункт нумерованного списка

Текст красного цвета
Текст синего цвета
Выделение желтым
/*Далее таблица*/
1.1
1.2
1.3
1.4
1.2
2.2
2.3
2.4
3.1
3.2
3.3
3.4

Ссылка на гуголь

/*Далее картинка*/

Закладка
Текст с отступом 2 см
Ссылка на сноску1Сноска на странице
.
Следует обратить внимание еще на пару обстоятельств. Все текстовые узлы в документе имеют нормализованную форму. То есть там нет текстов, которые содержат более одного пробела подряд или переходы на новые строки. Однако в документе такие места есть, поэтому интересно посмотреть, как это решается в коде документа. Вот так выглядит код элемента с разрывом строки
Код xml Выделить

<text:span text:style-name="T16">

  1.a;alfjasdf; lj l ;l lj ;lk <text:line-break/>lkj;lkj l sdls dfslkj as;l

</text:span>

Здесь элемент text:line-break по сути выполняет ту же роль, что и элемент br в HTML. Если кто не в курсе, то с клавиатуры это набирается путем ввода сочетания Shift+Enter. В этом случае новый абзац не создается, а просто обрывается строка. Другой случай - несколько пробелов подряд. В документе это тоже имеется, но приведу более чистый код
Код xml Выделить

<text:p text:style-name="P8">

  Текст до десяти пробелов <text:s text:c="9"/>Текст после десяти пробелов

</text:p>

Думаю, пояснения не нужны. Добавляем еще два шаблона
Код xml Выделить

<xsl:template match="text:s">

  <xsl:value-of select="for $s in (1 to @text:c) return ' '"/>

</xsl:template>

<xsl:template match="text:line-break">

  <xsl:text>

  </xsl:text>

</xsl:template>

Вот что имеем теперь
Кликните здесь для просмотра всего текста
Код xml Выделить

<?xml version="1.0" encoding="UTF-8"?>

<root>

  <![CDATA[

[COLOR="#2e74b5"]Заголовок 1[/COLOR]

Обычный текст

[COLOR="#2e74b5"]Заголовок 2[/COLOR]

[COLOR="#1f4d78"]Заголовок 3[/COLOR]

[COLOR="#2e74b5"]Заголовок 4[/COLOR]

 

[COLOR="#2e74b5"]Заголовок 5[/COLOR]

[COLOR="#1f4d78"]Заголовок 6[/COLOR]

[COLOR="#1f4d78"]Заголовок 7[/COLOR]

Название

[COLOR="#5a5a5a"]Подзаголовок[/COLOR]

[COLOR="#5b9bd5"]Сильное выделение[/COLOR]

Строгий

[COLOR="#404040"]Цитата 2[/COLOR]

[COLOR="#5a5a5a"]Слабая ссылка[/COLOR]

[COLOR="#5b9bd5"]Сильная ссылка[/COLOR]

 

Название книги

Абзац списка.

Жирный

Курисив

Подчеркнутый

Перечекнутый

ХНижний индекс

ХВерхний идекс

Крупный шрифт 72

Мелкий шрифт 8

Левое выравнивание

Выравнивание по центру

Правое выравнивание

Первый пункт маркированного списка

Второй пункт маркированного списка

 

Первый пункт                                                                                                           нумерованного списка

Пункт 1.a;alfjasdf; lj l ;l lj ;lk

lkj;lkj l sdls dfslkj as;l

Пункт 1.b b xj 'nj pf [eqyz&amp;

Второй пункт нумерованного списка

Текст до десяти пробелов                  Текст после десяти пробелов

[COLOR="#ff0000"]Текст красного цвета[/COLOR]

[COLOR="#00b0f0"]Текст синего цвета[/COLOR]

Выделение желтым

/*Далее таблица*/

1.1

1.2

1.3

1.4

1.2

2.2

2.3

2.4

3.1

3.2

3.3

3.4

 

[COLOR="#0563c1"]Ссылка на гуголь[/COLOR]

 

/*Далее картинка*/

 

Закладка

Текст с отступом 2 см

Ссылка на сноску1Сноска на странице

.

 

 

]]>

</root>


На самом деле дело не ограничивается только именами элементов. Конечно на способ отображения влияет и стиль и контекст. Если говорить о стилях, то у них есть такой атрибут, как style:family. Если он имеет значение paragraph, то элементы, к которым этот стиль относится видимо и будут блочными. Хотя, как видно даже из приведенного примера элементы такого типа вовсе не всегда должны обрабатываться одинаково. Например содержимое ячейки таблицы тоже включает text:p, но если мы будем каждую ячейку на новой строке размещать, то таблицы в BB-кодах уже не получится. Но это я уже вперед забежал. Пока нам достаточно того, что уже сделано.

Демонстрация работы подсветки синтаксиса кода



Ну, о чем-то реально полезном пока говорить рановато, но то, что мы уже сделали вполне можно посмотреть в работе. На данный момент наше преобразование имеет вид как во вложении (ColorizeTextOOFilter.zip).
Можно сохранить его в папке для фильтров и в дальнейшем использовать для тестов, предварительно добавив как фильтр в программу Writer. В Visual Studio имеется одна интересная особенность: когда из редактора кода копируется код, то в буфере обмена он сохраняется не только как текст, но и в формате RTF. Таким образом, когда он вставляется в программу, поддерживающую этот формат, то сохраняется подсветка синтаксиса. "Офисные" программы RTF поддерживают, а нам как раз интересно посмотреть на подсветку синтаксиса. Таким образом я скопирую часть кода нашего преобразования из студии, вставлю код в поле редактора и сохраню с помощью нашего фильтра.
Результат у меня получился вот такой
Код xml Выделить

<?xml version="1.0" encoding="UTF-8"?>

<root>

  <![CDATA[

   [COLOR="#0000ff"]<[/COLOR][COLOR="#2b91af"]xsl:template[/COLOR][COLOR="#0000ff"] [/COLOR][COLOR="#ff0000"]match[/COLOR][COLOR="#0000ff"]=[/COLOR][COLOR="#000000"]"[/COLOR][COLOR="#0000ff"]/[/COLOR][COLOR="#000000"]"[/COLOR][COLOR="#0000ff"]>[/COLOR]

       [COLOR="#0000ff"]<[/COLOR][COLOR="#a31515"]root[/COLOR][COLOR="#0000ff"]>[/COLOR]

           [COLOR="#0000ff"]<[/COLOR][COLOR="#2b91af"]xsl:text[/COLOR][COLOR="#0000ff"] [/COLOR][COLOR="#ff0000"]disable-output-escaping[/COLOR][COLOR="#0000ff"]=[/COLOR][COLOR="#000000"]"[/COLOR][COLOR="#0000ff"]yes[/COLOR][COLOR="#000000"]"[/COLOR][COLOR="#0000ff"]>[/COLOR]

[COLOR="#ff0000"]&lt;[/COLOR][COLOR="#000000"]![CDATA[[/COLOR]

[COLOR="#0000ff"]</[/COLOR][COLOR="#2b91af"]xsl:text[/COLOR][COLOR="#0000ff"]>[/COLOR]

 

           [COLOR="#0000ff"]<[/COLOR][COLOR="#2b91af"]xsl:apply-templates[/COLOR][COLOR="#0000ff"] [/COLOR][COLOR="#ff0000"]select[/COLOR][COLOR="#0000ff"]=[/COLOR][COLOR="#000000"]"[/COLOR][COLOR="#0000ff"]//office:body[/COLOR][COLOR="#000000"]"[/COLOR][COLOR="#0000ff"]/> [/COLOR]        

 

           [COLOR="#0000ff"]<[/COLOR][COLOR="#2b91af"]xsl:text[/COLOR][COLOR="#0000ff"] [/COLOR][COLOR="#ff0000"]disable-output-escaping[/COLOR][COLOR="#0000ff"]=[/COLOR][COLOR="#000000"]"[/COLOR][COLOR="#0000ff"]yes[/COLOR][COLOR="#000000"]"[/COLOR][COLOR="#0000ff"]>[/COLOR]

[COLOR="#000000"]]][/COLOR][COLOR="#ff0000"]&gt;[/COLOR]

[COLOR="#0000ff"]</[/COLOR][COLOR="#2b91af"]xsl:text[/COLOR][COLOR="#0000ff"]>[/COLOR]

       [COLOR="#0000ff"]</[/COLOR][COLOR="#a31515"]root[/COLOR][COLOR="#0000ff"]>[/COLOR]

   [COLOR="#0000ff"]</[/COLOR][COLOR="#2b91af"]xsl:template[/COLOR][COLOR="#0000ff"]>[/COLOR]

 

 

]]>

</root>

А вот как это выглядит после обработки BB-кодов
Цитата:
<xsl:templatematch="/">
<root>
<xsl:textdisable-output-escaping="yes">
&lt;![CDATA[
</xsl:text>

<xsl:apply-templatesselect="//office:body"/>

<xsl:textdisable-output-escaping="yes">
]]&gt;
</xsl:text>
</root>
</xsl:template>
Конечно, съедены отступы и пробелы между именами элементов и атрибутов, но в самом коде они есть. И главное вовсе не это, а то, что уже на данном этапе мы получили возможность автоматически окрашивать код в соответствии с тем, как он окрашен в документе, а в данном случае и в Visual Studio. Что касается проблемы с пробелами, то ее можно решить, заменив в выходном потоке пробелы символами с кодом 8194. Фильтр, в котором это сделано находится во вложении ColorizeTextooFilter_SpaceProblemCorrected.zip. А вот результат
Цитата:
   <xsl:templatematch="/">
         <root>
             <xsl:textdisable-output-escaping="yes">
  &lt;![CDATA[
  </xsl:text>
  
             <xsl:apply-templatesselect="//office:body"/>          
  
             <xsl:textdisable-output-escaping="yes">
  ]]&gt;
  </xsl:text>
         </root>
     </xsl:template>
Думаю, что тот, кто видел код XSLT в Visual Studio сможет по достоинству оценить результат. Хотя я не уверен, что такой код годится для копипасты, все-таки пробелы не настоящие.

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

Отправить комментарий