DXL: обработка с помощью XSL

NickProstoNick

Статус как статус :)
Lotus Team
22.08.2008
1 851
27
BIT
0
Есть форма.... на форме может быть до 5 таблиц в разных RT-полях.
Задача - разобрать одну из таблиц, определенную пользователем. Строки таблицы надо представить в виде отдельных респонсов.
Как лучше всего это сделать?
Подумываю в сторону XSLT... но вот до меня пока не очень доходит как выбрать нужную таблицу :rolleyes:
 
Последнее редактирование модератором:
если таблицы не отличаются - тока по порядку перебора (на нужном, в ХЛТ, номере обработать)
ежели есть теги - атрибуты
 
НЕТ... в том-то и дело... таблицы разные.
Ис XLT как-то не понимаю как работать :rolleyes:
 
с ХЛТ работать лучше через тулзы - мне приглянулась oXygen
у нее есть отладка...
но читать и осмысливать экзампелы - придется всё-равно
очень приблизительно:
назначаем темплэйт и описываем условие - под кот попадают ноды (в т.ч. атрибуты и прочая...)
в нек. условиях можно менять значения, в нек. - надо ноды удалять и добавлять новые
вот шаблон для РТ, но он тестовый и автогенерёный (недоделан) из препроцессора (самописный ХМЛ + ХСЛТ)
может на идеи натолкнет, шаблон превращал ДХЛ РТ в ХМЛ для ujac (вобщем не важно)
Код:
<?xml version="1.0" encoding="utf-8"?><!--
***********************************
Default template rule in generated
stylesheet.
***********************************
--><wh:stylesheet xmlns:wh="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.lotus.com/dxl" xmlns:ldn="http://www.lotus.com/dxl" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"><!--

***************************************
Template rule to strip and rename tags.
***************************************
-->
<wh:template match="ldn:run">
<wh:if test="(normalize-space(text()) or node()[name()!='font'])">
<wh:element name="font">
<wh:apply-templates select="ldn:font/@*"/>
<wh:apply-templates select="text()"/>
<wh:apply-templates select="./*[name()!='font']"/>
</wh:element>
</wh:if>
</wh:template><!--

******************
Template set root.
******************
-->
<wh:template match="/">
<wh:element name="richtext">
<wh:element name="font">
<wh:attribute name="style">default</wh:attribute>
<wh:apply-templates select="descendant::ldn:richtext/@* | descendant::ldn:richtext/node()"/>
</wh:element>
</wh:element>
</wh:template><!--

********************************
template rule to unwraping tags.
********************************
-->
<wh:template match="ldn:computedtext">
<wh:variable name="varbody">
<wh:apply-templates select="descendant::ldn:formula/@*"/>
<wh:variable name="replacing" select="descendant::ldn:formula/text()"/>
<wh:text>${</wh:text>
<wh:choose>
<wh:when test="substring-after($replacing,'"')">
<wh:value-of select="substring-before(substring-after($replacing,'"'),'"')"/>
</wh:when>
<wh:otherwise>
<wh:value-of select="$replacing"/>
</wh:otherwise>
</wh:choose>
<wh:text>}</wh:text>
</wh:variable>
<wh:value-of select="$varbody"/>
</wh:template><!--

******************************************************
template for attributes assembling
and wraping. Optional copy by @id then delete original
******************************************************
-->
<wh:template match="ldn:pardef"/>
<wh:template match="ldn:par">
<wh:variable name="id">
<wh:value-of select="./@def"/>
</wh:variable>
<wh:choose>
<wh:when test="preceding::ldn:pardef[@id=$id and string-length(@list)=0]">
<wh:call-template name="setelement">
<wh:with-param name="id">
<wh:value-of select="./@def"/>
</wh:with-param>
</wh:call-template>
</wh:when>
<wh:otherwise>
<wh:if test="string-length(preceding-sibling::ldn:*[@def=$id]/@def)=0">
<wh:element name="list">
<wh:call-template name="setelementlist">
<wh:with-param name="id">
<wh:value-of select="$id"/>
</wh:with-param>
</wh:call-template>
<wh:for-each select="following-sibling::ldn:*[@def=$id]">
<wh:call-template name="setelementlist">
<wh:with-param name="id">
<wh:value-of select="$id"/>
</wh:with-param>
</wh:call-template>
</wh:for-each>
</wh:element>
</wh:if>
</wh:otherwise>
</wh:choose>
</wh:template>
<wh:template name="loopdef">
<wh:param name="defid"/>
<wh:for-each select="following::ldn:par[@def=$defid]">
<wh:call-template name="setelement">
<wh:with-param name="id">
<wh:value-of select="./@def"/>
</wh:with-param>
</wh:call-template>
</wh:for-each>
</wh:template>
<wh:template name="setelement">
<wh:param name="id"/>
<wh:element name="paragraph">
<wh:variable name="wrapper">
<wh:if test="preceding::ldn:pardef[@id=$id]/@rightmargin != '100%'">padding-right:<wh:value-of select="preceding::ldn:pardef[@id=$id]/@rightmargin"/>;</wh:if>
<wh:if test="preceding::ldn:pardef[@id=$id]/@leftmargin != ''">padding-left:<wh:value-of select="preceding::ldn:pardef[@id=$id]/@leftmargin"/>;</wh:if>
</wh:variable>
<wh:if test="normalize-space($wrapper)">
<wh:attribute name="style">
<wh:value-of select="normalize-space($wrapper)"/>
</wh:attribute>
</wh:if>
<wh:apply-templates select="preceding::ldn:pardef[@id=$id]/@*[name()!='rightmargin' and name()!='leftmargin' and name()!='id' and name()!='tabs' and name()!='keepwithnext' and name()!='list']"/>
<wh:apply-templates select="node()"/>
</wh:element>
</wh:template>
<wh:template name="setelementlist">
<wh:param name="id"/>
<wh:element name="list-item">
<wh:variable name="wrapper">
<wh:if test="preceding::ldn:pardef[@id=$id]/@rightmargin != '100%'">padding-right:<wh:value-of select="preceding::ldn:pardef[@id=$id]/@rightmargin"/>;</wh:if>
<wh:if test="preceding::ldn:pardef[@id=$id]/@leftmargin != ''">padding-left:<wh:value-of select="preceding::ldn:pardef[@id=$id]/@leftmargin"/>;</wh:if>
</wh:variable>
<wh:if test="normalize-space($wrapper)">
<wh:attribute name="style">
<wh:value-of select="normalize-space($wrapper)"/>
</wh:attribute>
</wh:if>
<wh:apply-templates select="preceding::ldn:pardef[@id=$id]/@*[name()!='rightmargin' and name()!='leftmargin' and name()!='id' and name()!='tabs' and name()!='keepwithnext' and name()!='list']"/>
<wh:apply-templates select="node()"/>
</wh:element>
</wh:template>
<!--

**********************************
template rule to rename attribute.
**********************************
-->
<wh:template match="ldn:pardef/@keeptogether">
<wh:attribute name="keep-together">
<wh:value-of select="."/>
</wh:attribute>
</wh:template><!--

*****************************************
template rule to replace attribute value.
*****************************************
-->
<wh:template match="ldn:pardef/@align">
<wh:attribute name="align">
<wh:choose>
<wh:when test="(.)=substring-before('full;justified',';')">
<wh:value-of select="substring-after('full;justified',';')"/>
</wh:when>
<wh:otherwise>
<wh:value-of select="."/>
</wh:otherwise>
</wh:choose>
</wh:attribute>
</wh:template><!--

********************************
Create template rule to convert
elements to parent attribute.
********************************
-->
<wh:template match="ldn:table/@widthtype">
<wh:variable name="childs">
<wh:for-each select="parent::ldn:table/ldn:tablecolumn">
<wh:variable name="value">
<wh:value-of select="translate(./@width,'0123456789in%','0123456789')"/>
</wh:variable>
<wh:value-of select="$value"/>
<wh:if test="following-sibling::ldn:tablecolumn">
<wh:text>,</wh:text>
</wh:if>
</wh:for-each>
</wh:variable>
<wh:attribute name="widths">
<wh:value-of select="$childs"/>
</wh:attribute>
</wh:template>
<wh:template match="ldn:table/ldn:tablecolumn"/><!--

****************************
template rule to rename tag.
****************************
-->
<wh:template match="ldn:tablecell">
<wh:element name="cell">
<wh:apply-templates select="@*|node()"/>
</wh:element>
</wh:template><!--

****************************
template rule to rename tag.
****************************
-->
<wh:template match="ldn:tablerow">
<wh:element name="tr">
<wh:apply-templates select="@*|node()"/>
</wh:element>
</wh:template><!--

*********************************
Template rule to delete elements.
*********************************
-->
<wh:template match="ldn:table/@refwidth"/><!--

*********************************
Template rule to delete elements.
*********************************
-->
<wh:template match="ldn:table/@leftmargin"/>
<wh:template match="@*|node()">
<wh:copy>
<wh:apply-templates select="@*|node()"/>
</wh:copy>
</wh:template>
</wh:stylesheet>
 
lmike
из твоего примера подходящий кусок....
Код:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:wh="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.lotus.com/dxl" xmlns:ldn="http://www.lotus.com/dxl" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!--
****************************
template rule to rename tag.
****************************
-->
<wh:template match="ldn:item">
<wh:element name="TEST" >
<wh:apply-templates select="./*[name()]"/>
</wh:element>
</wh:template>
<wh:template match="ldn:tablecell">
<wh:element name="cell">
<wh:apply-templates select="./*[name()='par']"/>
</wh:element>
</wh:template>
<!--
****************************
template rule to rename tag.
****************************
-->
<wh:template match="ldn:tablerow">
<wh:element name="tr">
<wh:apply-templates select="@*|node()"/>
</wh:element>
</wh:template>
</xsl:stylesheet>
вот только одна загвоздка:
Код:
	<wh:template match="ldn:item">
<wh:element name="TEST" >
тут надо писать название item'a. А вот как - не пойму никак :rolleyes:
 
match находит элемент
element - перефигачивает на его место (т.е. создает на его месте новую ноду с именем)
<wh:apply-templates select="./*[name()='par']"/>
сохраняет (типа копирует) все подчиненные ноды по условию (остальные не будут скопированы)
мен не понятно - чего не понятно :rolleyes:
 
это я понял.... просто мне надо обрамить содержимое каким-нить элементом с именем или атрибутом как на форме
Из твоего примера выдрал кусок, который группирует таблицы.... осталось разделить таблицы... чтоб удобней перебирать было
чтоб получилось что-то в этом роде
Код:
<item name='Untitled3'>
<tr>
<cell>TEST</cell>
<cell>TEST1</cell></tr>
<tr>
<cell>TEST2</cell>
<cell>TEST2</cell></tr>
</item>

<item name='Untitled4'>
<tr>
<cell>TEST</cell>
<cell>TEST1</cell></tr>
<tr>
<cell>TEST2</cell>
<cell>TEST2</cell></tr>
</item>
Untitled3 и Untitled4 - поля на форме
 
фсё это уже глубокий офтопик..

можно получать все айтемы (по match - кот. есть xPath), можно их итерировать (есть циклы)
вот экзампел, но он с подстановками (в фиг. скобках) из др. XML (это кусок кода предпроцессора, кот. генерил код выше)
Код:
<xsl:comment>

********************************
Create template rule to convert
elements to parent attribute.
********************************
</xsl:comment>
<xsl:variable name="normattr" select="normalize-space(parattr)"/>
<xsl:variable name="parattr">
<xsl:value-of select="substring-before($normattr,';')"/>
</xsl:variable>
<xsl:variable name="myattr">
<xsl:choose>
<xsl:when test="substring-after($normattr,';')">
<xsl:value-of select="substring-after($normattr,';')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$parattr"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<wh:template match="ldn:{parent}/@{$parattr}">
<wh:variable name="childs">
<wh:for-each select="parent::ldn:{parent}/ldn:{child}">
<wh:variable name="value"><wh:value-of select="translate(./@{childattr},'0123456789in%','0123456789')"/></wh:variable>
<wh:value-of select="$value"/>
<wh:if test="following-sibling::ldn:{child}">
<wh:text>,</wh:text>
</wh:if>
</wh:for-each>
</wh:variable>
<!--	 <wh:message>Attrs:<wh:value-of select="$childs"/></wh:message>-->
<wh:attribute name="{$myattr}">
<wh:value-of select="$childs"/>
</wh:attribute>
</wh:template>
<!--Delete child nodes-->
<wh:template match="ldn:{parent}/ldn:{child}"/>
<!--
<wh:template match="{parent}">
<wh:apply-templates select="@*"/>
<wh:apply-templates select="text()"/>
<wh:apply-templates select="./*[name()!='{child}']"/>
</wh:template>
-->
</xsl:template>

единственно, надо помнить - переменные - одноразовые сущности и изменение их, напрямую, невозможно - только через процедуры (типа наращивать стринг и выдавать его длину - получим счетчик)
вот оторванный пример - "дербанит" стринг:
Код:
<!--
split-string
Parameters:
$all: a semicolon-separated string
$spliter: spliter string, default="|"
$swrapper: default="'"
Output: string separated by $spliter
-->
<xsl:template name="split-string">
<xsl:param name="all" />
<xsl:param name="spliter">|</xsl:param>
<xsl:param name="swrapper">'</xsl:param>
<!-- First word in $all: -->
<xsl:variable name="first" >
<xsl:variable name="first0" select="substring-before($all,';')" />
<xsl:choose>
<xsl:when test="$first0" >
<xsl:copy-of select="$first0" />
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$all" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>

<!-- <xsl:message>DEBUG $all=<xsl:value-of select="$all" />, $first="<xsl:value-of select="$first"/>"</xsl:message>
<xsl:message>DEBUG <xsl:value-of select="string-length($first)"/></xsl:message>
-->
<xsl:choose>
<xsl:when test="string-length($first)" >
<xsl:value-of select="$swrapper"/><xsl:value-of select="$first" /><xsl:value-of select="$swrapper"/>
<xsl:if test="substring-after($all,';')">
<xsl:value-of select="$spliter" />
<xsl:call-template name="split-string">
<xsl:with-param name="all" >
<!-- <xsl:message>DEBUG after:<xsl:value-of select="substring-after($all,';')" /></xsl:message>-->
<xsl:value-of select="substring-after($all,';')" />
</xsl:with-param>
<xsl:with-param name="spliter" select="$spliter"/>
<xsl:with-param name="swrapper" select="$swrapper"/>
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$swrapper"/><xsl:value-of select="$all"/><xsl:value-of select="$swrapper"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
 
забыл, атрибут (имя - тобишь, в данном вопросе), задаем как было выше
<wh:element name="TEST" >
<wh:attribute name="Untitled3">
....
либо через select (xPath у него - ./@name) и переменную
либо
<wh:attribute name="./@name">
 
lmike
Дякую! Похоже получилось то что хотелось :D
 
Всем привет!
Спустя несколько лет вернулся к вопросу формирования PDF на основе Lotus-формы.
Вот какой возник момент:
В xml стили в столбцах таблиц указаны неявно. Через ссылки на теги pardef.
Эти pardef могут быть в любом месте xml. На какой pardef идет ссылка можно определить из атрибута def тега par
xml.png


Так вот собственно вопрос: как бы правильно написать шаблон в xslt, чтоб мощно было забирать из нужного тега pardef значение атрибута align ?
Мне думалось, что должно быть как-то так:

XML:
    <xsl:template match="ldn:par" name="ldn:par">
        <xsl:choose>
            <xsl:when test="expression">
               
            </xsl:when>
           
            <xsl:otherwise>       
           
                <fo:block font-family="Arial" >
                   
                    <xsl:attribute name="text-align">   
                        <xsl:value-of select="pardef[@id=@def]/@align"/>                                                   
                    </xsl:attribute>

                    <xsl:apply-templates />       
                       
                    <fo:leader />
                   
                </fo:block>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
Но не работает. Для теста пробовал напрямую ссылаться на известный id, но результата так же не получил.
XML:
                    <xsl:attribute name="text-align">  
                        <xsl:value-of select="pardef[@id='30']/@align"/>                                                   
                    </xsl:attribute>
Вероятно, что шаблон работает в рамках своей выборки и по этому не находит теги глобально по фалу.
Обходной маневр - это программно добавить в исходный xml теги pardef везде где есть ссылка на него, но так делать не хочется.
 
я уже разобрался... Выражение должно быть следующего вида:
XML:
                    <xsl:attribute name="text-align">
                        <xsl:variable name="def" select="@def"></xsl:variable>
                        <xsl:value-of select="//ldn:pardef[@id=$def]/@align"/>
                    </xsl:attribute>
Было (третья колонка):
683.png


Стало (третья колонка):
684.png

[doublepost=1503394859,1503309801][/doublepost]Вот финальный вариант верстки:
pdf.png
 
@NickProstoNick если есть возможность - желательно полный XSLT , для всех, выложить
 
Я уже как-то тут делился этим шаблоном....
Если в документе для конвертации будут атачи - то в PDF-файле будет пометка (см. файл <имя файла>)
Финальная версия в архиве
[doublepost=1503673779,1503490985][/doublepost]Выкладываю очередную последнюю версию :)
В данной версии:
- "причесал" шаблоны. частично избавился от мусора;
- добавил возможность цеплять файлы в PDF;
- в тексте сделал ссылки на вложенные файлы вида (см. файл <имя файла>).
- исправил некоторые ошибки в шаблонах. Из всех ошибок и предупреждений осталось только это
25 серп 2017 18:49:56 org.apache.fop.events.LoggingEventListener processEvent
INFO: An fo:table (No context info available) is wider than the available room in inline-progression-dimension. Adjusting end-indent based on overconstrained geometry rules (XSL 1.1, ch. 5.3.4)
25 серп 2017 18:49:56 org.apache.fop.events.LoggingEventListener processEvent
INFO: An fo:table (No context info available) is wider than the available room in inline-progression-dimension. Adjusting end-indent based on overconstrained geometry rules (XSL 1.1, ch. 5.3.4)
25 серп 2017 18:49:56 org.apache.fop.fonts.truetype.OpenFont handleCharacterSpacing
WARNING: Encountered format constraint violation in advanced (typographic) table (AT) in font 'Arial Bold', ignoring AT data: unsupported class definition table format: 0
25 серп 2017 18:49:58 org.apache.fop.events.LoggingEventListener processEvent
INFO: Rendered page #1.
25 серп 2017 18:49:58 org.apache.fop.events.LoggingEventListener processEvent
INFO: Rendered page #2.

С вложенными файлами есть нюанс - в AdobeReade "плывут" названия файлов с кириллицей и не открываются и не детачатся файлы zip и rar (по крайней мере я столкнулся только с этими файлами)
687.png

Это решается модификацией реестра. Необходимо модифицировать запись
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Adobe\Acrobat Reader\11.0\FeatureLockDown\cDefaultLaunchAttachmentPerms
Именно модифицировать, т.к. zip и rar в этом списке записаны как запрещенные
ПОДРОБНЕЕ

Ну и собственно результат работы.
Верстка в Lotus (шапка с картинкой добавлена в дизайней формы, а текст с файлами - в RT-поле)
pdf.png


Ну и результат отрисовки в PDF
pdf_rez.png

[doublepost=1503909081][/doublepost]Очередная последняя версия :)
На выходных подумалось, что надо сделать границы таблицы по умолчанию, а то пользователям не объяснишь зачем выставлять цвет границ. Их же и так видно.
[doublepost=1511164071][/doublepost]Смотрю, что ветка "померла", но вопрос задам.
Намедни столкнулся с проблемой: в PDF не работают Notes-ссылки вида notes://..... (виндовый проводник ссылки открывает).
Кто-то сталкивался с такой проблемой?
 

Вложения

  • Нравится
Реакции: rinsk, alexas1 и lmike
Тема похоже мертва, но все же попробую...
Кто-то пробовал писать xsl-шаблон для обработки html?
Меня интересует работа со стилями в теге <style>
 
Тема похоже мертва, но все же попробую...
Кто-то пробовал писать xsl-шаблон для обработки html?
Меня интересует работа со стилями в теге <style>
это будет дичь ;) - ведь обработка проистекает на уровне тегов, а далее - изменение атрибутов/содержимого (в виде текста)
по сути - будет работа с текстом...
CSS - это уровень презентэйшн, а не стр-ры
или речь о чем-то другом?
 
это будет дичь ;) - ведь обработка проистекает на уровне тегов, а далее - изменение атрибутов/содержимого (в виде текста)
по сути - будет работа с текстом...
Меня интересует конвертация HTML-страницы с применением стилей из тега <style> в PDF.
Как распарсить атрибуты из html-тегов более-менее понятно, а вот как парсить <style> - не ясно
 
Меня интересует конвертация HTML-страницы с применением стилей из тега <style> в PDF.
Как распарсить атрибуты из html-тегов более-менее понятно, а вот как парсить <style> - не ясно
там все очень...
общие соображения
сам так не делал...
еще момент - XSL-FO уже считается устаревшим...
 
Да, я видел эту презентацию, но вот примеров я так и не нашел.
CSSToXSLFO интересно, но информации очень мало. Примеров и описания css и файла данных так и не нашел :(
Есть еще идея использовать библиотеки OpenOffice. Думаю будет проще и надежней
 
Последнее редактирование:
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!