如果列包含特定值(在本例中为“我想要你”),我试图在特定列中的所有节点中添加一个值(在本例中为字符串“I Added This”) )使用XSLT 2.0。
这意味着,如果我有下表:
<table>
<tr>
<th>header value</th>
<th>I Want You</th>
<th>header value</th>
</tr>
<tr>
<td>value 1</td>
<td>value 2</td>
<td>value 3</td>
</tr>
<tr>
<td>value 4</td>
<td>value 5</td>
<td>value 6</td>
</tr>
</table>
在我应用xslt脚本之后输出应该是这个:
<table>
<tr>
<th>header value</th>
<th>I Want You</th>
<th>header value</th>
</tr>
<tr>
<td>value 1</td>
<td>I Added This value 2</td>
<td>value 3</td>
</tr>
<tr>
<td>value 4</td>
<td>I Added This value 5</td>
<td>value 6</td>
</tr>
</table>
为了实现这一点,我写了很多不同的样式表,但我甚至没有接近:
复制整个表格:
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
这让我得到了我想要更改的列的值 - 但是从那里我不知道如何使用短语“我添加此值”来添加每个td值
<xsl:template match="//th[contains(lower-case(.), 'I Want You')]">
<xsl:variable name="tdPos" select="count(preceding-sibling::td)+2"/>
<xsl:for-each select="current()/parent::*/following-sibling::tr">
<xsl:value-of select="./td[$tdPos]/text()"/>
</xsl:for-each>
</xsl:template>
非常感谢任何可能指向正确方向的提示!
答案 0 :(得分:1)
值得注意的一个问题是你的“包含”测试不太正确
<xsl:template match="//th[contains(lower-case(.), 'I Want You')]">
可能是以下
<xsl:template match="//th[contains(lower-case(.), lower-case('I Want You'))]">
但是,如果您参数化搜索值,可能会更好,尽管您无法在模板匹配中使用此参数。相反,你只会匹配任何细胞......
<xsl:template match="tr/*">
然后,您可以测试前一行上的等效列是否具有您想要的值
<xsl:if
test="../preceding-sibling::tr/*[$position][contains(., $match)]">
(为简洁起见,删除了小写()命令
这里$ position将是一个包含当前单元格位置的变量,$ match是您要查找的变量。
尝试以下XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:param name="match" select="'I Want You'" />
<xsl:param name="add" select="'I Added This'" />
<xsl:template match="tr/*">
<xsl:variable name="position" select="count(preceding-sibling::*) + 1"/> <xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:if test="../preceding-sibling::tr/*[$position][contains(lower-case(.), lower-case($match))]">
<xsl:value-of select="concat($add, ' ')" />
</xsl:if>
<xsl:apply-templates select="text()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
应用于XML时,会生成以下内容
<table>
<tr>
<th>header value</th>
<th>I Want You</th>
<th>header value</th>
</tr>
<tr>
<td>value 1</td>
<td>I Added This value 2</td>
<td>value 3</td>
</tr>
<tr>
<td>value 4</td>
<td>I Added This value 5</td>
<td>value 6</td>
</tr>
</table>
当应用于此XML
时<table>
<tr>
<th>header value</th>
<th>header value</th>
<th>header value</th>
</tr>
<tr>
<td>value 1</td>
<td>I Want You</td>
<td>value 2</td>
</tr>
<tr>
<td>value 3</td>
<td>value 4</td>
<td>value 5</td>
</tr>
</table>
以下是输出
<table>
<tr>
<th>header value</th>
<th>header value</th>
<th>header value</th>
</tr>
<tr>
<td>value 1</td>
<td>I Want You</td>
<td>value 2</td>
</tr>
<tr>
<td>value 3</td>
<td>I Added This value 4</td>
<td>value 5</td>
</tr>
</table>
答案 1 :(得分:1)
你是在正确的路线上 - 你只需要在输出节点时做一个条件,这样在TD节点的情况下,检查同一索引处的表兄TH节点是否具有所需的文本。
<xsl:template match="*|@*">
<xsl:variable name='curr_pos' select='position()' />
<xsl:copy>
<xsl:apply-templates select='@*' />
<xsl:if test='name() = "td" and /table/tr[1]/th[$curr_pos] = "I Want You"'>prefix - </xsl:if>
<xsl:value-of select='text()' />
<xsl:apply-templates select='*' />
</xsl:copy>
</xsl:template>
您可以在this playground session运行它。
答案 2 :(得分:1)
可能是最短和最简单的转换(无preceding-sibling::
,无position()
,无条件指令,无变量):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="tr/*[2]/text()[not(. = 'I Want You')]">
<xsl:value-of select="concat('I Added This ', .)"/>
</xsl:template>
</xsl:stylesheet>
在提供的XML文档上应用此转换时:
<table>
<tr>
<th>header value</th>
<th>I Want You</th>
<th>header value</th>
</tr>
<tr>
<td>value 1</td>
<td>value 2</td>
<td>value 3</td>
</tr>
<tr>
<td>value 4</td>
<td>value 5</td>
<td>value 6</td>
</tr>
</table>
产生了想要的正确结果:
<table>
<tr>
<th>header value</th>
<th>I Want You</th>
<th>header value</th>
</tr>
<tr>
<td>value 1</td>
<td>I Added This value 2</td>
<td>value 3</td>
</tr>
<tr>
<td>value 4</td>
<td>I Added This value 5</td>
<td>value 6</td>
</tr>
</table>
<强>解释强>:
身份规则“按原样”复制每个匹配的节点。
有一个覆盖模板。它匹配任何文本节点,其字符串值不是字符串'I Want You'
和,它是任何元素的子元素(因此th
和td
都匹配)这是tr
的第二个子元素。此模板输出字符串'I Added This '
的串联和当前(匹配)节点的字符串值。
请注意:这是一个XSLT 1.0解决方案,但它与XSLT 2.0处理器的工作方式相同,完全没有任何更改。将version
的{{1}}属性更改为“2.0”是安全的(如果是nessecary)。
答案 3 :(得分:0)
谢谢Tim C!它的工作就像一个魅力,它是一个非常好的解决方案!虽然如果文档中有多个表格,我会遇到一些问题,但我会应用此样式表。它还会在不包含“我想要你”值的表中添加值。任何解决方法?我尝试选择所有表格然后单独运行其列,但这导致没有输出。
<xsl:template match="//table">
<xsl:for-each select="/tr/*">
<xsl:variable name="position" select="position()" />
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:if test="../preceding-sibling::tr/*[position() = $position][contains(lower-case(.), lower-case($match))]">
<xsl:value-of select="concat($add, ' ')" />
</xsl:if>
<xsl:apply-templates select="text()"/>
</xsl:copy>
</xsl:for-each>
</xsl:template>
答案 4 :(得分:0)
此样式表(也适用于XSLT 1.0)...
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="td">
<xsl:variable name="col" select="count(preceding-sibling::td)+1" />
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:if test="contains(../../tr[1]/th[$col], 'I Want You')">
<xsl:value-of select="'I Added This '" />
</xsl:if>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
...当应用于您的样本输入时,将产生您所需的输出。
蒂姆的回答是不正确的,或者至少不是一贯正确的。 position()函数很棘手。问题是position()包括空白节点和你在html表中可能有的其他非表格内容,例如微数据格式。如果标题行中的白色间距与数据行不同,则Tim C的解决方案将无效。 count()是必需的。我故意将小写()位移掉。我将测试的细节留给了OP。
此外,还有一个更简单的XSLT 2.0解决方案......
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="td[
for $col in position() return
contains(../../tr[1]/th[$col], 'I Want You')]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:value-of select="'I Added This '" />
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 5 :(得分:0)
这是一个简短,正确的答案,在任何<th>
中处理“我想要这个”,并且在包含大量此类表格的文档中工作(如果它们在语义上是正确的)。
当这个XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- Template #1 - Identity Template -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- Template #2 -->
<xsl:template match="tr[position() > 1]/td[position() = count(../../th[. = 'I Want You']/preceding-sibling::th) + 1]/text()">
<xsl:value-of select="concat('I Added This ', .)" />
</xsl:template>
</xsl:stylesheet>
适用于此XML文档:
<table>
<tr>
<th>header value</th>
<th>I Want You</th>
<th>header value</th>
</tr>
<tr>
<td>value 1</td>
<td>value 2</td>
<td>value 3</td>
</tr>
<tr>
<td>value 4</td>
<td>value 5</td>
<td>value 6</td>
</tr>
</table>
产生了想要的结果:
<?xml version="1.0" encoding="UTF-8"?>
<table>
<tr>
<th>header value</th>
<th>I Want You</th>
<th>header value</th>
</tr>
<tr>
<td>value 1</td>
<td>I Added This value 2</td>
<td>value 3</td>
</tr>
<tr>
<td>value 4</td>
<td>I Added This value 5</td>
<td>value 6</td>
</tr>
</table>
请注意,如果文档中有多个此类<table>
元素,则此XSLT也会涵盖该情况。这不是你特别要求的,但它不在可能的范围之外,所以我想我会覆盖它。
<强> XML:强>
<body>
<table>
<tr>
<th>header value</th>
<th>I Want You</th>
<th>header value</th>
</tr>
<tr>
<td>value 1</td>
<td>value 2</td>
<td>value 3</td>
</tr>
<tr>
<td>value 4</td>
<td>value 5</td>
<td>value 6</td>
</tr>
</table>
<table>
<tr>
<th>I Want You</th>
<th>header value</th>
<th>header value</th>
</tr>
<tr>
<td>value 1</td>
<td>value 2</td>
<td>value 3</td>
</tr>
<tr>
<td>value 4</td>
<td>value 5</td>
<td>value 6</td>
</tr>
</table>
</body>
<强>结果:强>
<?xml version="1.0" encoding="UTF-8"?><body>
<table>
<tr>
<th>header value</th>
<th>I Want You</th>
<th>header value</th>
</tr>
<tr>
<td>value 1</td>
<td>I Added This value 2</td>
<td>value 3</td>
</tr>
<tr>
<td>value 4</td>
<td>I Added This value 5</td>
<td>value 6</td>
</tr>
</table>
<table>
<tr>
<th>I Want You</th>
<th>header value</th>
<th>header value</th>
</tr>
<tr>
<td>I Added This value 1</td>
<td>value 2</td>
<td>value 3</td>
</tr>
<tr>
<td>I Added This value 4</td>
<td>value 5</td>
<td>value 6</td>
</tr>
</table>
</body>
<强>解释强>
模板#1 - 身份模板 - 按原样复制所有内容。我们会在后续模板中覆盖此模板。
模板#2 - 此模板与XPath的doozy匹配:获取位置与<td>
元素匹配的<th>
元素中包含的所有文本(在最近的“标题”<tr>
),其值为“我想要你”。对于此文本,返回一个新值,即“我添加此内容”和原始文本的串联。