微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

XSLT XML 到 HTML 的 2 阶段转换 - 必须是更好的方法

如何解决XSLT XML 到 HTML 的 2 阶段转换 - 必须是更好的方法

我们收到一个价格变化的 XML 数据包,然后想要更新 HTML 文档的特定部分。问题是我们可以看到它工作的唯一方法是通过 2 阶段转换,首先将 XML 数据包转换为格式良好的 HTML 块,然后使用第二个 XSLT 读取 HTML 文件并覆盖该特定部分。

要更新的 HTML 文件(格式正确):

<html>
  <head>
    <title>Mini-me Amazon</title>
  </head>
  <body>
    <p>This is our Product Price Sheet</p>
    <table style="width:100%">
      <tr>
        <th>Product</th>
        <th>Price</th>
      </tr>
      <tr data-key="1">
        <td>Whiz-bang widget</td>
        <td name="price1">$19.99</td>
      </tr>
      <tr data-key="3">
        <td>Unreal widget</td>
        <td name="price3">$99.99</td>
      </tr>
      ...
    </table>
  </body>
</html>

传入的 XML:

<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet type="text/xsl" href="xml-price.xsl"?>
<supplier>
  <product>
    <key>3</key>
    <pprice uptype="1">
      <price>$22.34</price>
    </pprice>
  </product>
</supplier>

一个 XSL:

<xsl:stylesheet ...>
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:template match="/supplier">
    <xsl:apply-templates select="product"/>
  </xsl:template>
  <xsl:template match="product">
    <xsl:variable name="PKey">
      <xsl:value-of select="key"/>
    </xsl:variable>
    <xsl:for-each select="pprice">  <!-- Could be more than 1 -->
      <xsl:choose>
        <xsl:when test="@uptype=0">
        </xsl:when>
        <xsl:when test="@uptype=1">
          <xsl:apply-templates select="price"/>
        </xsl:when>
        <xsl:otherwise>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="price">
      <td name="rate$PKey"><xsl:value-of select="."/></td>
  </xsl:template>
</xsl:stylesheet>

所以 Saxon-js 返回一个 <td name="price3">$22.34</td>。都好。所以我们想要获取这个 HTML 块并更新 HTML。

第二个 XSL:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes"/>
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="td[@name='price3']">   <!-- Problem 1 -->
    <td name="price3">$22.34</td>             <!-- Problem 2 --> 
  </xsl:template>
  <xsl:template match="/">
    <xsl:apply-templates select="document('/home/tireduser/node/bigstuff/public/update-html.html')/node()"/>
  </xsl:template>
</xsl:stylesheet>

问题:

我们如何将 price3<td name="price3">$22.34</td> 的动态值(它们更改传入的每个新 XML)放入第二个 XSL 中,而无需将 XSL 重新编译为 Saxon- Node.js 需要并且不使用参数来传入这些值(因为我们已经读过不推荐使用参数? 或者所有这些都可以在 1 次转换中完成?

第二个问题:Saxon-js 文档说明:

Using fn:transform()
If a source XSLT stylesheet is supplied as input to the fn:transform() function in XPath,the XX compiler will be invoked to compile the stylesheet before it is executed. However,there is no way of capturing the intermediate SEF stylesheet for subsequent re-use.

我们发现这不是真的(或者做错了)。如果我们只是将 XSL 传递给 Transform 函数 (stylesheetFileName:),则会产生错误

解决方法

我认为您基本上想要一个与

类似的样式表
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all"
  expand-text="yes">
  
  <xsl:param name="price-data">
<supplier>
  <product>
    <key>3</key>
    <pprice uptype="1">
      <price>$22.34</price>
    </pprice>
  </product>
</supplier>
  </xsl:param>
  
  <xsl:key name="price" match="product/pprice[@uptype = 1]/price" use="'price' || ancestor::product/key"/>

  <xsl:mode on-no-match="shallow-copy"/>
  
  <xsl:template match="td[@name][key('price',@name,$price-data)]/text()">{key('price',../@name,$price-data)}</xsl:template>

  <xsl:template match="/" name="xsl:initial-template">
    <xsl:next-match/>
    <xsl:comment>Run with {system-property('xsl:product-name')} {system-property('xsl:product-version')} {system-property('Q{http://saxon.sf.net/}platform')}</xsl:comment>
  </xsl:template>
  
</xsl:stylesheet>

Here is an online sample 在浏览器中使用 Saxon-JS 2

为了紧凑起见,我在参数中内联了辅助数据,对于 Saxon-JS 2 和 Node.js,您基本上可以声明参数绑定一个值,例如<xsl:param name="price-data" select="doc('sample2.xml')"/> 或者您可以使用 getResource 预加载文档,然后在运行转换之前将参数设置为预加载的文档;请参阅 https://www.saxonica.com/saxon-js/documentation/index.html#!api/getResource 中的示例部分。

在您的评论中,您说您将 XML 数据作为字符串从 Node.js 传递到 Saxon-JS,在这种情况下,您需要使用 parse-xml

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all"
  expand-text="yes">
  
  <xsl:param name="price-data" as="xs:string"><![CDATA[
<supplier>
  <product>
    <key>3</key>
    <pprice uptype="1">
      <price>$22.34</price>
    </pprice>
  </product>
</supplier>
  ]]></xsl:param>
  
  <xsl:param name="price-doc" select="parse-xml($price-data)"/>
  
  <xsl:key name="price" match="product/pprice[@uptype = 1]/price" use="'price' || ancestor::product/key"/>

  <xsl:mode on-no-match="shallow-copy"/>
  
  <xsl:template match="td[@name][key('price',$price-doc)]/text()">{key('price',$price-doc)}</xsl:template>

  <xsl:template match="/" name="xsl:initial-template">
    <xsl:next-match/>
    <xsl:comment>Run with {system-property('xsl:product-name')} {system-property('xsl:product-version')} {system-property('Q{http://saxon.sf.net/}platform')}</xsl:comment>
  </xsl:template>
  
</xsl:stylesheet>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。