1

我们得到一个价格变化的 XML 数据包,然后想要更新 HTML 文档的特定部分。问题是我们可以看到它工作的唯一方法是通过两阶段转换,首先将 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>

问题:

我们如何在不将 XSL 重新编译成 Saxon-js 需要的 .sef.json 并且不使用参数传入这些值的情况下,将price3and的动态值(改变每个新的 XML 传入)到第二个 XSL 中(<td name="price3">$22.34</td>既然我们已经读过不推荐使用参数?或者这一切都可以在 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:),则会产生错误。

4

1 回答 1

2

我认为你基本上想要一个单一的样式表

<?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>

这是在浏览器中使用 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', @name, $price-doc)]/text()">{key('price', ../@name, $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>
于 2021-03-11T07:56:24.137 回答