提问人:MadeFrame 提问时间:9/30/2023 最后编辑:MadeFrame 更新时间:9/30/2023 访问量:50
XSLT 字符串到节点的转换和 disable-output-escaping
XSLT string to node conversion and disable-output-escaping
问:
我正在将 Access 数据库导出为 XML,然后需要转换 XML 以准备数据,以便 Framemaker 创建出版物。在此过程中,我需要在 Access 输出的文本中创建交叉引用。目前,我的方法是插入 <idref>some text</idref>,但是当导出到 XML 时,这变成了 <一些文字>,正因为如此,我使用的 html 解析器并没有像我希望的那样将文本转换为节点。我有 Saxon EE 9.8.3,但尚未测试 html-parse,因为上一个问题中提供的解决方案能够解决我最初的解析问题。(使用 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>
我实际上有一个“解决方案”,因为我可以使用禁用输出转义,但我在其他地方看到这是一个更高级的工具,而且通常它不是理想的解决方案。这是解决我问题的最佳方法吗?
*请注意,我使用的是 David Carlisle 的 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>
答:
1赞
Siebe Jongebloed
9/30/2023
#1
您的 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>
评论
0赞
MadeFrame
9/30/2023
谢谢,显然我还有很多东西要学。我仍然不完全确定为什么解析需要第二次运行,并且在匹配 Description 时第一次没有捕获和创建节点,但您在这里的第一个解决方案有效,我更喜欢使用它来使用我在问题中的代码。
0赞
MadeFrame
9/30/2023
我现在遇到的一个问题是,如果我复制 <idref&燃气轮机;PR001F</idref&燃气轮机;并将其放在 Description 节点中而不是 listitem 中,那么它不会转换为节点,但是当我将它放在 listitem 中时,它确实会转换。我错过了什么?
0赞
Siebe Jongebloed
10/1/2023
添加了一个完整的 xslt,它可能会解决您更改的示例
评论