XSLT 计数器递归和传递参数



我已经能够创建一个XSLT(包含)将源XML转换为目标所需的XML格式(包含),但是我相信可以利用一些内置的XSLT功能来优化这一点,这些功能超出了我的熟练程度。欣赏任何想法。

核心要求是输入XML包含标头值和数据(第一条记录包含标头/标签,后续记录包含这些相应标签的数据,因此输出数据与第一条记录在位置上匹配),输出XML包含名称值对,名称描述数据元素(来自源中第一条记录的标头/标签),元素为"labelXX","值XX",因此需要计数器来递增 XX。输出还包含一个标头记录,该记录基本上只包含元素的名称,其余部分从输出中是不言自明的。

源 XML

<?xml version="1.0" encoding="UTF-8"?>
<SpecExportFF>
<recordset>
<value>12345</value>
<value>xyz</value>
<value>a0</value>
<value>b0</value>
<value>c0</value>
<value>d0</value>
<value>e0</value>
<value>f0</value>
<value>g0</value>
<value>h0</value>
<value>i0</value>
<value>j0</value>
<value>k0</value>
<value>l0</value>
<value>m0</value>
<value>n0</value>
<value>o0</value>
<value>p0</value>
<value>q0</value>
<value>r0</value>
<value>s0</value>
<value>t0</value>
<value>a1</value>
<value>b1</value>
<value>c1</value>
<value>d1</value>
<value>e1</value>
<value>f1</value>
<value>g1</value>
<value>h1</value>
<value>i1</value>
<value>j1</value>
<value>k1</value>
<value>l1</value>
<value>m1</value>
<value>n1</value>
<value>o1</value>
<value>p1</value>
<value>q1</value>
<value>r1</value>
<value>s1</value>
<value>t1</value>
<value>a2</value>
<value>b2</value>
<value>c2</value>
<value>d2</value>
<value>e2</value>
<value>f2</value>
<value>g2</value>
<value>h2</value>
<value>i2</value>
<value>j2</value>
<value>k2</value>
<value>l2</value>
<value>m2</value>
<value>n2</value>
<value>o2</value>
<value>p2</value>
<value>q2</value>
<value>r2</value>
<value>s2</value>
<value>t2</value>
</recordset>
<recordset>
<value>A12345</value>
<value>snacks</value>
<value>1</value>
<value>cereals</value>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
</recordset>
<recordset>
<value>A245678</value>
<value>snacks</value>
<value>1</value>
<value>chips</value>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value>potato</value>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value>fried</value>
<value/>
<value></value>
<value/>
<value>baked</value>
<value></value>
<value></value>
<value></value>
<value/>
<value></value>
<value/>
<value>20g</value>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value/>
<value></value>
</recordset>
</SpecExportFF>

输出目标 XML

<?xml>
itemcategorylabel01spec01label02spec02 <2/spec02 标签03>标签03<规格03>规格03<标签04>标签04<规格04>规格04<标签05>标签05<规格05>规格05<标签06>标签06<规格06>规格06<标签07>标签07<规格07>规格07<标签08>标签08<规格08>规格08<标签09>标签09<规格09>规格 09label10spec10label11spec11label12spec12label13<规格13>规格13<标签14>标签14<规格14>规格14<标签15>标签15<规格15>规格15<标签16>标签16<规格16>规格16<标签 _x0031_7=">标签17<规格17>规格17<标签18>标签18<规格18>规格18<标签19>标签19<规格19>规格19<标签20>标签20<规格20>spec20label21spec21label22spec22label23spec23label24spec24label25spec25label26spec26label27spec27<标签28>标签28<规格28>规格28<标签29>标签29<规格29>规格29<标签30>标签30<规格30>规格30<标签31>标签31<规格31>规格 31<标签32>标签32<规格32>规格32<标签33>标签33<规格33>规格33<标签34>标签34<规格34>规格34<标签35>标签35<规格35>规格35<标签36>标签36<规格36>规格36<标签37>标签37<规格37>规格37<标签38>标签38<规格38>规格38<标签 _x0033_9=">标签39<规格39>规格39<标签40>标签40<规格40>规格40<标签41>标签41<规格41>规格41<标签42>标签42<规格42>spec42label43spec43label44spec44label45spec45label46spec46label47spec47label48spec48label49spec49<标签50>标签50<规格50>规格50<标签51>标签51<规格51>规格51<标签52>标签52<规格52>规格52<标签53>标签53<规格53>规格 53<标签54>标签54<规格54>规格54<标签55>标签55<规格55>规格55<标签56>标签56<规格56>规格56<标签57>标签57<规格57>规格57<标签58>标签58<规格58>规格58<标签59>标签59<规格59>规格59<标签60>标签60<规格60>规格60
A12345snacksa01b0cereals<项目>A245678<类别>零食<标签01>A0<规格01>1<标签02>B0<规格02>芯片<标签03>Q0<规格03>土豆 <3 label04>e1friedi1bakedp120g
我的XSLT(它可以工作,但我认为太复杂了,并希望对其进行优化)
<?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" indent="yes"/>
<xsl:template match="/SpecExportFF">
<SpecExportOutputFF>
<xsl:for-each select="recordset">
<xsl:variable name="IndexOfCurrentRecordset">
<xsl:value-of select="position()"/>
</xsl:variable>
<xsl:if test="$IndexOfCurrentRecordset = 1">
<header>
<xsl:for-each select="value">
<xsl:variable name="IndexOfCurrentNode" select="position()"/>
<xsl:variable name="ElementSuffix" select="format-number(($IndexOfCurrentNode - 2),'00')"/>
<!--<hello1><xsl:value-of select="$IndexOfCurrentNode"/></hello1>-->
<xsl:choose>
<xsl:when test="$IndexOfCurrentNode = 1">
<xsl:element name="item">item</xsl:element>
</xsl:when>
<xsl:when test="$IndexOfCurrentNode = 2">
<xsl:element name="category">category</xsl:element>
</xsl:when>
<xsl:when test="($IndexOfCurrentNode > 2)">
<xsl:element name="{concat('label',$ElementSuffix)}">
<xsl:value-of select="concat('label',$ElementSuffix)"/>
</xsl:element>
<xsl:element name="{concat('spec',$ElementSuffix)}">
<xsl:value-of select="concat('spec',$ElementSuffix)"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</header>
</xsl:if>
<xsl:if test="$IndexOfCurrentRecordset > 1">
<data>
<xsl:call-template name="iterate_values">
<xsl:with-param name="i" select="1"/>
<xsl:with-param name="currentNode" select="./value[1]"/>
<xsl:with-param name="IndexOfCurrentRecordset" select="$IndexOfCurrentRecordset"/>
<xsl:with-param name="IndexOfCurrentNode" select="1"/>
</xsl:call-template>
</data>
</xsl:if>
</xsl:for-each>
</SpecExportOutputFF>
</xsl:template>
<xsl:template name="iterate_values">
<xsl:param name="i"/>
<xsl:param name="currentNode"/>
<xsl:param name="IndexOfCurrentRecordset"/>
<xsl:param name="IndexOfCurrentNode"/>
<xsl:variable name="ElementSuffix" select="format-number($i,'00')"/>
<xsl:choose>
<xsl:when test="$IndexOfCurrentNode = 1">
<xsl:element name="item">
<xsl:value-of select="$currentNode/text()"/>
</xsl:element>
<xsl:if test="/SpecExportFF/recordset[position() = $IndexOfCurrentRecordset]/value[position() = $IndexOfCurrentNode+1]">
<xsl:call-template name="iterate_values">
<xsl:with-param name="i" select="$i"/>
<xsl:with-param name="currentNode" select="/SpecExportFF/recordset[position() = $IndexOfCurrentRecordset]/value[position() = $IndexOfCurrentNode+1]"/>
<xsl:with-param name="IndexOfCurrentRecordset" select="$IndexOfCurrentRecordset"/>
<xsl:with-param name="IndexOfCurrentNode" select="$IndexOfCurrentNode+1"/>
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:when test="$IndexOfCurrentNode = 2">
<xsl:element name="category">
<xsl:value-of select="$currentNode/text()"/>
</xsl:element>
<xsl:if test="/SpecExportFF/recordset[position() = $IndexOfCurrentRecordset]/value[position() = $IndexOfCurrentNode+1]">
<xsl:call-template name="iterate_values">
<xsl:with-param name="i" select="$i"/>
<xsl:with-param name="currentNode" select="/SpecExportFF/recordset[position() = $IndexOfCurrentRecordset]/value[position() = $IndexOfCurrentNode+1]"/>
<xsl:with-param name="IndexOfCurrentRecordset" select="$IndexOfCurrentRecordset"/>
<xsl:with-param name="IndexOfCurrentNode" select="$IndexOfCurrentNode+1"/>
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:when test="$IndexOfCurrentNode > 2 and $currentNode/text() != ''">
<xsl:element name="{concat('label',$ElementSuffix)}">
<xsl:value-of select="/*/*[1]/value[$IndexOfCurrentNode]"/>
</xsl:element>
<xsl:element name="{concat('spec',$ElementSuffix)}">
<xsl:value-of select="$currentNode/text()"/>
</xsl:element>
<xsl:if test="/SpecExportFF/recordset[position() = $IndexOfCurrentRecordset]/value[position() = $IndexOfCurrentNode+1]">
<xsl:call-template name="iterate_values">
<xsl:with-param name="i" select="$i+1"/>
<xsl:with-param name="currentNode" select="/SpecExportFF/recordset[position() = $IndexOfCurrentRecordset]/value[position() = $IndexOfCurrentNode+1]"/>
<xsl:with-param name="IndexOfCurrentRecordset" select="$IndexOfCurrentRecordset"/>
<xsl:with-param name="IndexOfCurrentNode" select="$IndexOfCurrentNode+1"/>
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:if test="/SpecExportFF/recordset[position() = $IndexOfCurrentRecordset]/value[position() = $IndexOfCurrentNode+1]">
<xsl:call-template name="iterate_values">
<xsl:with-param name="i" select="$i"/>
<xsl:with-param name="currentNode" select="/SpecExportFF/recordset[position() = $IndexOfCurrentRecordset]/value[position() = $IndexOfCurrentNode+1]"/>
<xsl:with-param name="IndexOfCurrentRecordset" select="$IndexOfCurrentRecordset"/>
<xsl:with-param name="IndexOfCurrentNode" select="$IndexOfCurrentNode+1"/>
</xsl:call-template>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

只是为了挑战,我弄清楚了你想做什么。我认为主要问题是你正在势在必行地思考,但需要改变你的思维方式,因为XSLT是一种函数式语言,事情是非常不同的。

事实上,这就是我想出的...

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:variable name="labels" select="/SpecExportFF/recordset[1]/value[position() > 2]" />
<xsl:template match="SpecExportFF">
<SpecExportOutputFF>
<xsl:apply-templates select="recordset" />
</SpecExportOutputFF>
</xsl:template>
<xsl:template match="recordset[1]">
<header>
<item>item</item>
<category>category</category>
<xsl:for-each select="value">
</xsl:for-each> 
</header>
</xsl:template>
<xsl:template match="recordset[1]">
<header>
<item>item</item>
<category>category</category>
<xsl:for-each select="value[position() > 2]">
<xsl:variable name="ElementSuffix" select="format-number(position(),'00')"/>
<xsl:element name="{concat('label',$ElementSuffix)}">
<xsl:value-of select="concat('label',$ElementSuffix)"/>
</xsl:element>
<xsl:element name="{concat('spec',$ElementSuffix)}">
<xsl:value-of select="concat('spec',$ElementSuffix)"/>
</xsl:element>
</xsl:for-each> 
</header>
</xsl:template>
<xsl:template match="recordset">
<data>
<item><xsl:value-of select="value[1]" /></item>
<category><xsl:value-of select="value[2]" /></category>
<xsl:for-each select="value[position() > 2][normalize-space()]">
<xsl:variable name="ElementSuffix" select="format-number(position(),'00')"/>
<xsl:variable name="LabelPos" select="count(preceding-sibling::value) - 1" />
<xsl:element name="{concat('label',$ElementSuffix)}">
<xsl:value-of select="$labels[position() = $LabelPos]" />
</xsl:element>
<xsl:element name="{concat('spec',$ElementSuffix)}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</data>
</xsl:template>
</xsl:stylesheet>

最新更新