在 XML 中使用 parse-xml 将 文本 转换为 节点

Using parse-xml to convert text to node in XML

提问人:MadeFrame 提问时间:9/28/2023 更新时间:9/28/2023 访问量:51

问:

我正在处理来自 Access 数据库的 XML 输出,其中某些节点中的文本需要通过 XSLT 转换为节点本身,然后通过 Adobe FrameMaker 运行以创建出版物。在网上看,我看到了很多对 XSLT 函数的引用,我应该有一个名为 parse-xml(Framemaker 的 XSLT 可以使用 Saxon 9.8),它应该允许我做我正在尝试做的事情。我还没有找到使用此函数的单个示例,而且我仍然对 XSLT 很陌生,以至于我无法想象代码的正确构造。此外,如果您知道基于 Web 的 XSLT 3.0 测试器,那将是一个很大的帮助。我一直在使用 XSLtransform.net 这很棒,但它不支持 XSLT 3.0(至少像 Framemaker 一样通过 Saxon 9.8)。

我的XML我需要转换:

<?xml version="1.0" encoding="UTF-8"?>
<dataroot xmlns:od="urn:schemas-microsoft-com:officedata" generated="2023-09-26T10:37:15">
<TEQuery>
<IntID>PR090F</IntID>
<TEName>Exempt Lease From Taxable Owner</TEName>
<Description>

&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;&amp;nbsp;Leased properties that qualify for this exemption are reported under one of the following expenditures: &lt;/font&gt;&lt;/div&gt;

&lt;ul&gt;
 &lt;ul&gt;
  &lt;ul&gt;
   &lt;ul&gt;
    &lt;ul&gt;
     &lt;ul&gt;
      &lt;ul&gt;
       &lt;li&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;PR001F, &lt;/font&gt;&lt;/li&gt;
       &lt;li&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;PR007F,&lt;/font&gt;&lt;/li&gt;
       &lt;li&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;PR079F, &lt;/font&gt;&lt;/li&gt;
       &lt;li&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;PR083F, &lt;/font&gt;&lt;/li&gt;
       &lt;li&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;PR085F, &lt;/font&gt;&lt;/li&gt;
       &lt;li&gt;&lt;font face=&quot;Times New Roman&quot; color=black&gt;PR086F, &lt;/font&gt;&lt;/li&gt;
      &lt;/ul&gt;
     &lt;/ul&gt;
    &lt;/ul&gt;
   &lt;/ul&gt;
  &lt;/ul&gt;
 &lt;/ul&gt;
&lt;/ul&gt;
</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>
&lt;div&gt;&lt;font face="Times New Roman" color=black&gt;&amp;nbsp;Leased properties that qualify for this exemption are reported under one of the following expenditures: &lt;/font&gt;&lt;/div&gt;
<unorderedlist>
       <listitem>;&lt;font face="Times New Roman" color=black&gt;PR001F, &lt;/font&gt;</listitem>
       <listitem>;&lt;font face="Times New Roman" color=black&gt;PR007F, &lt;/font&gt;</listitem>
       <listitem>&lt;font face="Times New Roman" color=black&gt;PR079F, &lt;/font&gt;</listitem>
       <listitem>&lt;font face="Times New Roman" color=black&gt;PR083F, &lt;/font&gt;</listitem>
       <listitem>&lt;font face="Times New Roman" color=black&gt;PR085F, &lt;/font&gt;</listitem>
       <listitem>&lt;font face="Times New Roman" color=black&gt;PR086F, &lt;/font&gt;</listitem>
   </unorderedlist>
   </TaxExpenditure>
</dataroot>

这是我当前的 XSL 代码,除了将列表字符串转换为节点之外,它可以做到目前为止的所有事情,但我 100% 迷失了 parse-xml 函数的后续步骤,无论它应该驻留在 xsl:template 语句中还是其他东西,等等。在删除“<字体...”时可以提供的任何帮助通过 xslt 的文本的“<div>”部分也将不胜感激,尽管我怀疑我可能需要在 xslt 之外的过程中稍后执行此操作,或者在删除它们之前将它们也转换为节点。

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

<xsl:template match="/ | @* | node()">
        <xsl:copy>
               <xsl:apply-templates select="@* | node()" />
         </xsl:copy>
 </xsl:template>

<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="IntID"/>
<xsl:template match="TaxSort"/>
<xsl:template match="TEName"/>
</xsl:stylesheet>
xml 解析 xslt-3.0

评论

0赞 Martin Honnen 9/28/2023
的内容包含一些不正确的 XML 标记(即 将产生错误,因为属性值没有引号分隔符。Description&lt;div&gt;&lt;font face=&quot;Times New Roman&quot; color=blackcolor

答:

0赞 Martin Honnen 9/28/2023 #1

正如我在评论中指出的那样,根据 XML 规则,元素的内容格式不正确,因为至少有一些属性值没有正确用引号字符分隔。Description

因此,既不能也不能成功解析该内容。parse-xmlparse-xml-fragment

检查您在 Framemaker 中的 Saxon 版本/版本是否是商业版本(即 PE 或 EE),然后您可以使用(取决于确切的版本)扩展函数 https://www.saxonica.com/html/documentation10/functions/saxon/parse-html.html 或新的 XPath 4 。saxon:parse-htmlfn:parse-html

另一方面,在纯 XSLT 2 中有一个不错的小 HTML 标签汤解析器实现,即 David Carlisle 的 https://github.com/davidcarlisle/web-xslt/blob/main/htmlparse/htmlparse.xsl,您可以导入然后像(假设命名空间声明)一样使用它,例如xmlns:dc="data:,dpc"

<xsl:import href="https://raw.githubusercontent.com/davidcarlisle/web-xslt/main/htmlparse/htmlparse.xsl"/>

<xsl:template match="Description">
  <xsl:copy>
    <xsl:apply-templates select="dc:htmlparse(., '', true())"/>
  </xsl:copy>
</xsl:template>

然后你基本上将HTML作为XDM节点(例如,,,元素节点),您可以添加模板来转换它们,例如divfontulli

<xsl:template match="li">
  <listitem>
   <xsl:apply-templates/>
  </listitem>
</xsl:template>

目前尚不清楚您是否真的想要一些结果元素,例如 but then inside again 转义标记;当然,您可以序列化节点,尽管这将在解析它们之后,并使用 XSLT 允许和 Saxon 实现的序列化(例如,可能在属性值周围使用引号),这意味着不可能保留原始转义标记。listitemfn:serialize

至于在浏览器中摆弄 XSLT 3,https://martin-honnen.github.io/xslt3fiddle/ 使用 SaxonJS(目前为 2.5)(您的示例和我的 XSLT 建议),然后我 https://xsltfiddle.liberty-development.net/ 有 Saxon 10,https://xsltfiddle-beta.liberty-development.net/ 有各种 Saxon 版本。

请记住,https://xsltfiddle.liberty-development.net/ 允许您将小提琴存储在数据库中,但随后您可以与网络共享它们,因此请确保不要保存任何包含私有输入数据或要保密的代码的内容。

评论

0赞 MadeFrame 9/29/2023
嗨,@martin-honnen,非常感谢您的评论和各种资源的链接。我在这里有一个我希望问的原始问题的变体。如有必要,我可以将其作为单独的问题发布。如果我更改上面的文本只是为了将 PR001F 替换为 &lt;idref&燃气轮机;PR001F&lt;/idref&燃气轮机;有没有办法使用 HTML 解析器将其转换为 idref 元素?我的 Access 数据库以这种方式吐出“<”和“>”,它无法使用 David Carlisle 的上述代码。
0赞 MadeFrame 9/29/2023
此外,FrameMaker 使用 Saxon Enterprise Edition 9.8.3,因此,如果 parse-html 对这个问题的特定补充效果更好,我很想看看它将如何实现。
0赞 Martin Honnen 9/29/2023
@MadeFrame,请将该新问题单独发布为单独的问题,将所有详细信息。至于使用,也许也可以根据现有的示例和文档 saxonica.com/html/documentation9.8/functions/saxon/ 自己尝试一下......,如果你不能让它工作,问一个新问题,详细说明你尝试了什么以及它是如何失败的。最后,它只是另一个要调用的函数和一些用于处理函数返回的节点的模板。与我发布的代码相比,它可能会将 HTML 元素放在 XHTML ns 中。saxon:parse-html