我搜索并接近寻找解决方案,但这需要使用样式表2.0,而我仍然坚持使用1.0。
这是我的示例XML:
<root>
<row>A1: Apples</row>
<row>B1: Red</row>
<row>C1: Reference text</row>
<row>badly formatted text which belongs to row above</row>
<row>and here.</row>
<row>D1: ABC</row>
<row>E1: 123</row>
<row>A1: Oranges</row>
<row>B1: Purple</row>
<row>C1: More References</row>
<row>with no identifier</row>
<row>again and here.</row>
<row>D1: DEF</row>
<row>E1: 456</row>
.
.
我希望它看起来像:
<root>
<row>
<A1>Apples</A1>
<B1>Red</B1>
<C1>Reference text badly formatted text which belongs to row above and here.</C1>
<D1>ABC</D1>
<E1>123</E1>
</row>
<row>
<A1>Oranges</A1>
<B1>Purple</B1>
<C1>More Reference with no identifier again and here.</C1>
<D1>DEF</D1>
<E1>456</E1>
</row>
.
.
有一种模式,我可以使用其他实用程序进行转换,但使用XSL 1.0非常困难。
我可以使用元素中的标题,并且当转换为XML时,引用文本字段是多行的,它为每一行创建自己的行但它总是在C1之间的相同位置和D1。元素的实际名称,即不重要。
在E1之后该行应该分解。我认为我的例子是直截了当的,但这种转变不是。我认为自己甚至不是XML / XSL的初学者。我正在从头学习,然后我转移到其他项目,然后再次回到它。 TIA。
更新:我碰到的另一种情况略有不同,但我希望结果是一样的:
<root>
<row>
<Field>A1: Apples</Field>
</row>
<row>
<Field>B1: Red</Field>
</row>
<row>
<Field>C1: Reference text</Field>
</row>
<row>
<Field>badly formatted text which belongs to row above</Field>
</row>
<row>
<Field>and here.</Field>
</row>
<row>
<Field>D1: ABC</Field>
</row>
<row>
<Field>E1: 123</Field>
</row>
<row>
<Field>A1: Oranges</Field>
</row>
<row>
<Field>B1: Purple</Field>
</row>
<row>
<Field>C1: More References</Field>
</row>
<row>
<Field>with no identifier</Field>
</row>
<row>
<Field>again and here.</Field>
</row>
<row>
<Field>D1: DEF</Field>
</row>
<row>
<Field>E1: 456</Field>
</row>
我尝试应用身份转换,但似乎没有效果:
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match ="row/Field">
<xsl:apply-templates/>
</xsl:template>
答案 0 :(得分:0)
这看起来有点棘手,但我有一个似乎有用的解决方案。它允许在C1行之后有可变数量的行(它不清楚这是否总是2行)。
该解决方案大量使用following-sibling
轴,这可能非常低效,特别是对于大型输入文件。
您可以测试here。
<xsl:template match="/root">
<!-- Loop through every "A1" row -->
<xsl:for-each select="row[substring-before(text(), ':') = 'A1']">
<!-- Add a <row> tag -->
<xsl:element name="row">
<!-- Add each of the A1-E1 tags by finding the first following-sibling that matches before the colon -->
<xsl:apply-templates select="." />
<xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'B1'][1]" />
<xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'C1'][1]" />
<xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'D1'][1]" />
<xsl:apply-templates select="following-sibling::*[substring-before(text(), ':') = 'E1'][1]" />
</xsl:element>
</xsl:for-each>
</xsl:template>
<!-- Process each row -->
<xsl:template match="/root/row">
<!-- Create an element whose name is whatever is before the colon in the text -->
<xsl:element name="{substring-before(text(), ':')}">
<!-- Output everything after the colon -->
<xsl:value-of select="normalize-space(substring-after(text(), ':'))" />
<!-- Special treatment for the C1 node -->
<xsl:if test="substring-before(text(), ':') = 'C1'">
<!-- Count how many A1 nodes exist after this node -->
<xsl:variable name="remainingA1nodes" select="count(following-sibling::*[substring-before(text(), ':') = 'A1'])" />
<!-- Loop through all following-siblings that don't have a colon at position 3, and still have the same number of following A1 rows as this one does -->
<xsl:for-each select="following-sibling::*[substring(text(), 3, 1) != ':'][count(following-sibling::*[substring-before(text(), ':') = 'A1']) = $remainingA1nodes]">
<xsl:text> </xsl:text>
<xsl:value-of select="." />
</xsl:for-each>
</xsl:if>
</xsl:element>
</xsl:template>
答案 1 :(得分:0)
每个记录或组都是7行。
那为什么不单纯用数字来做呢:
XSLT 1.0
<?xml version="1.0" encoding="UTF-8"?>
<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="/root">
<root>
<xsl:for-each select="row[position() mod 7 = 1]">
<row>
<xsl:apply-templates select=". | following-sibling::row[position() < 3] | following-sibling::row[4 < position() and position() < 7]"/>
</row>
</xsl:for-each>
</root>
</xsl:template>
<xsl:template match="row">
<xsl:element name="{substring-before(., ': ')}">
<xsl:value-of select="substring-after(., ': ')"/>
</xsl:element>
</xsl:template>
<xsl:template match="row[starts-with(., 'C1: ')]">
<C1>
<xsl:value-of select="substring-after(., 'C1: ')"/>
<xsl:for-each select="following-sibling::row[position() < 3]">
<xsl:text> </xsl:text>
<xsl:value-of select="."/>
</xsl:for-each>
</C1>
</xsl:template>
</xsl:stylesheet>