用XSL将一个包含两列的表格拆分,其中每个逻辑列由多列组成
我想把一些遗留输出带入现代,将一个HTML表格转换成XML格式。
遗留输出按每行两列列出(product、price、order_number、amount),因此实际上它是这样的:
(product_n, price_n, order_number_n, amount_n, product_m, price_m, order_number_m, amount_m)
处理表格拆分的XSL部分是
<xsl:template match="tr">
<item>
<xsl:apply-templates select="th | td" mode="map-cols" />
</item>
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="td" mode="map-cols">
<!-- input uses "two column (with four columns each) rows -->
<xsl:variable name="rcol" select="(position() - 1) mod 4" />
<xsl:choose>
<xsl:when test="$rcol = 0"><!-- product -->
<xsl:if test="position() = 5">
</item><item>
</xsl:if>
<name>
<xsl:value-of select="normalize-space()" />
</name>
</xsl:when>
...
</xsl:choose>
</xsl:template>
问题在于 </item><item> 被原样输出;在那之前我用过 </item><item>,但那会导致解析错误:
解析器错误:开启和结束标签不匹配
显然我想在第5 列处结束当前的 item,并在第5 列处开始一个新的 item。
怎么做?
我正在使用 libxslt-tools-1.1.34-150400.3.13.1.x86_64 的SLES15。
输入示例
应要求,我在勾勒输入数据,但其实是一团糟。
事实上我发现表格在 amount_n 和 product_m 之间还多了一个空的“分隔列”,但为了与原始描述保持一致,我已经把它移除了。
所以如你所警告的,这里给出一个示例表格行:
<html>
<head>
<title>Example</title>
</head>
<body>
<!-- more stuff -->
<table frame='void' rules='all' cellspacing=1 cellpadding=0.9 style='BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid; BORDER-COLLAPSE: collapse'>
<tr>
<td width=210px><span style='font-size:8.0pt;mso-bidi-font-size:12.0pt'> Ba...</span></td>
<td width=30px align=right><span style='font-size:8.0pt;mso-bidi-font-size:12.0pt'>3,90 </span></td>
<td width=30px><span style='font-size:8.0pt;mso-bidi-font-size:12.0pt'> 1111</span></td>
<td width=34px><span style='font-size:8.0pt;mso-bidi-font-size:12.0pt'> </span></td>
<td width=210px><span style='font-size:8.0pt;mso-bidi-font-size:12.0pt'> Mi...</span></td>
<td width=30px align=right><span style='font-size:8.0pt;mso-bidi-font-size:12.0pt'>9,80 </span></td>
<td width=30px><span style='font-size:8.0pt;mso-bidi-font-size:12.0pt'> 2222</span></td>
<td width=34px><span style='font-size:8.0pt;mso-bidi-font-size:12.0pt'> </span></td>
</tr>
</table>
<!-- more stuff -->
</body>
</html>
(原始数据值b 已经被混淆,因为我不允许分享那些)
输出示例
...
<item>
<product>Ba...</product>
<price>3,90</price>
<ordernr>1111</ordernr>
</item>
<item>
<product>Mi...</product>
<price>9,80</price>
<ordernr>2222</ordernr>
</item>
...
(另一个挑战是按例如 product 对项进行排序;原始表格已经排序,因此第一行中第二个项的起始项紧跟在最后一行的第一个项之后)
解决方案
下面给出一个简化示例,供你作为指南。
输入(在同一行的两个项之间包含一个“分隔列”):
<html>
<body>
<table>
<tr>
<td>Product A</td>
<td>3,90</td>
<td>1111</td>
<td>4</td>
<td></td>
<td>Product B</td>
<td>9,80</td>
<td>2222</td>
<td>10</td>
</tr>
<tr>
<td>Product C</td>
<td>5,30</td>
<td>3333</td>
<td>3</td>
<td></td>
<td>Product D</td>
<td>10,40</td>
<td>4444</td>
<td>16</td>
</tr>
</table>
</body>
</html>
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/html">
<output>
<xsl:for-each select="body/table/tr/td[position() = 1 or position() = 6] ">
<item>
<product>
<xsl:value-of select="."/>
</product>
<price>
<xsl:value-of select="following-sibling::td[1]"/>
</price>
<order_number>
<xsl:value-of select="following-sibling::td[2]"/>
</order_number>
<amount>
<xsl:value-of select="following-sibling::td[3]"/>
</amount>
</item>
</xsl:for-each>
</output>
</xsl:template>
</xsl:stylesheet>
结果
<?xml version="1.0" encoding="UTF-8"?>
<output>
<item>
<product>Product A</product>
<price>3,90</price>
<order_number>1111</order_number>
<amount>4</amount>
</item>
<item>
<product>Product B</product>
<price>9,80</price>
<order_number>2222</order_number>
<amount>10</amount>
</item>
<item>
<product>Product C</product>
<price>5,30</price>
<order_number>3333</order_number>
<amount>3</amount>
</item>
<item>
<product>Product D</product>
<price>10,40</price>
<order_number>4444</order_number>
<amount>16</amount>
</item>
</output>
附加说明:
原始表格已经排序,因此第一行中第二个项的起始项紧随最后一行的第一个项之后
你可以只做很小的调整就保留原始顺序:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/html">
<output>
<xsl:call-template name="process">
<xsl:with-param name="cells" select="body/table/tr/td[1]"/>
</xsl:call-template>
<xsl:call-template name="process">
<xsl:with-param name="cells" select="body/table/tr/td[6]"/>
</xsl:call-template>
</output>
</xsl:template>
<xsl:template name="process">
<xsl:param name="cells"/>
<xsl:for-each select="$cells">
<item>
<product>
<xsl:value-of select="."/>
</product>
<price>
<xsl:value-of select="following-sibling::td[1]"/>
</price>
<order_number>
<xsl:value-of select="following-sibling::td[2]"/>
</order_number>
<amount>
<xsl:value-of select="following-sibling::td[3]"/>
</amount>
</item>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。