Я экспортирую базу данных Access в XML, затем мне нужно преобразовать XML, чтобы подготовить данные для Framemaker для создания публикации. В процессе мне нужно создать перекрестные ссылки в тексте вывода Access. На данный момент мой подход заключается в вставке <idref>некоторого текста</idref>, но при экспорте в XML это превращается в &lt;некоторый текст&gt;, и из-за этого синтаксический анализатор html, который я использую, выглядит следующим образом: не конвертируя текст в узел, как мне хотелось бы. У меня Saxon EE 9.8.3, но я не тестировал анализ html, поскольку решение, представленное в предыдущем вопросе, помогло решить мои первоначальные проблемы с анализом. (Использование parse-xml для преобразования текста в узел XML)
Вот версия ввода XML:
<?xml version = "1.0" encoding = "UTF-8"?>
<dataroot xmlns:od = "urn:schemas-microsoft-com:officedata" generated = "2023-09-29T08:29:47">
<TEQuery>
<IntID>PR090F</IntID>
<TEName>Exempt Lease From Taxable Owner</TEName>
<Description>
<div><font face="Times New Roman" color=black>&nbsp;Leased &lt;idref&gt;PR001F&lt;/idref&gt; properties that qualify for this exemption are reported under one of the following expenditures: </font></div>
<ul>
<ul>
<ul>
<ul>
<ul>
<ul>
<ul>
<li><font face="Times New Roman" color=black>&lt;idref&gt;PR001F&lt;/idref&gt;, </font></li>
<li><font face="Times New Roman" color=black>PR007F, </font></li>
<li><font face="Times New Roman" color=black>PR079F, </font></li>
<li><font face="Times New Roman" color=black>PR083F, </font></li>
<li><font face="Times New Roman" color=black>PR085F, </font></li>
<li><font face="Times New Roman" color=black>PR086F, </font></li>
<li><font face="Times New Roman" color=black>PR087F, .</font></li>
</ul>
</ul>
</ul>
</ul>
</ul>
</ul>
</ul></Description>
<TaxSort>2</TaxSort>
</TEQuery>
</dataroot>
Мой желаемый результат:
<dataroot xmlns:od = "urn:schemas-microsoft-com:officedata"
generated = "2023-09-26T10:37:15">
<TaxExpenditure id = "PR090F" TAXSORT = "2">Exempt Lease From Taxable Owner
<Description>
Leased <idref>PR001F</idref> properties that qualify for this exemption are reported under one of the following expenditures:
<unorderedList>
<listitem><idref>PR001F</idref>, </listitem>
<listitem>PR007F, </listitem>
<listitem>PR079F, </listitem>
<listitem>PR083F, </listitem>
<listitem>PR085F, </listitem>
<listitem>PR086F, </listitem>
<listitem>PR087F, </listitem>
</unorderedList>
</TaxExpenditure>
</dataroot>
На самом деле у меня есть «решение»: я могу использовать экранирование отключения вывода, но я видел в другом месте, что это более продвинутый инструмент, и часто это не идеальное решение. Это лучший подход к решению моей проблемы?
*Обратите внимание, что я использую htmlparse Дэвида Карлайла, который можно использовать с XSLT 2.0.
Вот XSLT, который я использую:
<xsl:stylesheet version = "3.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:dc = "data:,dpc"
exclude-result-prefixes = "#all">
<xsl:output method = "xml" omit-xml-declaration = "yes" encoding = "UTF-8" indent = "yes" />
<xsl:import href = "https://raw.githubusercontent.com/davidcarlisle/web-xslt/main/htmlparse/htmlparse.xsl"/>
<xsl:mode on-no-match = "shallow-copy"/>
<xsl:template match = "TEQuery">
<TaxExpenditure>
<xsl:attribute name = "id" select = "IntID"/>
<xsl:attribute name = "TAXSORT" select = "TaxSort"/>
<xsl:value-of select = "TEName"/>
<xsl:apply-templates select = "@* | node()" />
</TaxExpenditure>
</xsl:template>
<xsl:template match = "Description">
<xsl:copy>
<xsl:apply-templates select = "dc:htmlparse(., '', true())"/>
</xsl:copy>
</xsl:template>
<xsl:template match = "li">
<listitem>
<xsl:value-of disable-output-escaping = "yes" select = "."/>
</listitem>
</xsl:template>
<xsl:template match = "idref">
<idref>
<xsl:apply-templates/>
</idref>
</xsl:template>
<xsl:template match = "ul[ul] | font | div">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match = "ul[not(ul)]">
<unorderedList>
<xsl:apply-templates/>
</unorderedList>
</xsl:template>
<xsl:template match = "IntID"/>
<xsl:template match = "TaxSort"/>
<xsl:template match = "TEName"/>
</xsl:stylesheet>
Итак, в базе данных Access мне нужно иметь возможность разрешить пользователям добавлять какой-то текст, который после преобразования в XML и последующего преобразования превратится в узел xml. Тот точный текст, который я добавляю в ячейку базы данных и который вы процитировали, затем преобразуется при экспорте в формате XML в то, что отображается в моем входном XML. Думаю, я понимаю, что вы говорите о лексическом XML и узлах, но я не знаю, как обойти это из-за рабочего процесса, который у меня есть через Access, поэтому я думаю, что цель состоит в том, чтобы преобразовать эту лексическую строку в узел.





Ваш xslt уже дает ожидаемый результат. Но я вижу 2 альтернативы
Кажется, что dc:htmlparse может обрабатывать все виды (недопустимого) HTML, так почему бы не вызвать dc:htmlparse еще раз на <xsl:template match = "li"> вот так:
<xsl:template match = "li">
<listitem>
<xsl:apply-templates select = "dc:htmlparse(., '', true())"/>
</listitem>
</xsl:template>
Если вы уверены, что вставляете действительный XML, вы также можете использовать:
<xsl:template match = "li">
<listitem>
<xsl:apply-templates select = "parse-xml-fragment(.)"/>
</listitem>
</xsl:template>
РЕДАКТИРОВАТЬ
Этот xslt будет иметь дело с рекурсивным экранированным XML:
<xsl:stylesheet version = "3.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" xmlns:dc = "data:,dpc" exclude-result-prefixes = "#all">
<xsl:output method = "xml" omit-xml-declaration = "yes" encoding = "UTF-8" indent = "yes" />
<xsl:import href = "https://raw.githubusercontent.com/davidcarlisle/web-xslt/main/htmlparse/htmlparse.xsl"/>
<xsl:mode on-no-match = "shallow-copy"/>
<xsl:template match = "TEQuery">
<TaxExpenditure>
<xsl:attribute name = "id" select = "IntID"/>
<xsl:attribute name = "TAXSORT" select = "TaxSort"/>
<xsl:value-of select = "TEName"/>
<xsl:apply-templates select = "@* | node()" />
</TaxExpenditure>
</xsl:template>
<!-- This template does (optional recursively) what you need without the need of matching specific elements-->
<xsl:template match = "text()[contains(.,'<')]">
<xsl:apply-templates select = "dc:htmlparse(., '', true())"/>
</xsl:template>
<xsl:template match = "ul[ul] | font | div">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match = "ul[not(ul)]">
<unorderedList>
<xsl:apply-templates/>
</unorderedList>
</xsl:template>
<xsl:template match = "IntID"/>
<xsl:template match = "TaxSort"/>
<xsl:template match = "TEName"/>
</xsl:stylesheet>
Спасибо, видимо мне еще многому предстоит научиться. Я до сих пор не совсем уверен, почему синтаксический анализ должен запускаться второй раз и не улавливать и не создавать узлы в первый раз при сопоставлении с описанием, но ваше первое решение здесь работает, и я предпочитаю использовать его для кода, который у меня был в вопросе. .
У меня сейчас возникла одна проблема: если я скопирую файл &lt;idref&gt;PR001F&lt;/idref&gt; и поместите его в узел «Описание», а не в элемент списка, тогда он не преобразуется в узел, но когда он у меня есть в элементе списка, он преобразуется. Что мне там не хватает?
Добавлен полный xslt, который, вероятно, решит ваш измененный пример.
Вы говорите: «Мой подход состоит в том, чтобы вставить <idref>некоторый текст</idref>», но неясно, во что и как вы это вставляете. Если это в конечном итоге будет экранировано, это будет выглядеть так, как будто вы вставляете лексический XML в виде текста в проанализированную древовидную структуру XML. Если у вас есть проанализированная древовидная структура, вы должны вставлять в нее узлы, а не лексические строки XML.