我已经能够创建一个XSLT(包含)来将源XML转换为目标所需的XML格式(包括在内),但我确信这可以利用一些超出我熟练程度的内置XSLT功能进行优化。感谢任何想法。
核心要求是输入XML包含标题值和数据(第一个记录包含标题/标签,后续记录包含相应标签的数据,因此输出数据在位置上与第一个记录匹配),OutPut XML包含Name值对,名称描述数据元素(来自源中第一个记录的标题/标签),元素是" labelXX"," valueXX",因此需要计数器增加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 version="1.0" encoding="UTF-8"?> <SpecExportOutputFF> <header> <item>item</item> <category>category</category> <label01>label01</label01> <spec01>spec01</spec01> <label02>label02</label02> <spec02>spec02</spec02> <label03>label03</label03> <spec03>spec03</spec03> <label04>label04</label04> <spec04>spec04</spec04> <label05>label05</label05> <spec05>spec05</spec05> <label06>label06</label06> <spec06>spec06</spec06> <label07>label07</label07> <spec07>spec07</spec07> <label08>label08</label08> <spec08>spec08</spec08> <label09>label09</label09> <spec09>spec09</spec09> <label10>label10</label10> <spec10>spec10</spec10> <label11>label11</label11> <spec11>spec11</spec11> <label12>label12</label12> <spec12>spec12</spec12> <label13>label13</label13> <spec13>spec13</spec13> <label14>label14</label14> <spec14>spec14</spec14> <label15>label15</label15> <spec15>spec15</spec15> <label16>label16</label16> <spec16>spec16</spec16> <label17>label17</label17> <spec17>spec17</spec17> <label18>label18</label18> <spec18>spec18</spec18> <label19>label19</label19> <spec19>spec19</spec19> <label20>label20</label20> <spec20>spec20</spec20> <label21>label21</label21> <spec21>spec21</spec21> <label22>label22</label22> <spec22>spec22</spec22> <label23>label23</label23> <spec23>spec23</spec23> <label24>label24</label24> <spec24>spec24</spec24> <label25>label25</label25> <spec25>spec25</spec25> <label26>label26</label26> <spec26>spec26</spec26> <label27>label27</label27> <spec27>spec27</spec27> <label28>label28</label28> <spec28>spec28</spec28> <label29>label29</label29> <spec29>spec29</spec29> <label30>label30</label30> <spec30>spec30</spec30> <label31>label31</label31> <spec31>spec31</spec31> <label32>label32</label32> <spec32>spec32</spec32> <label33>label33</label33> <spec33>spec33</spec33> <label34>label34</label34> <spec34>spec34</spec34> <label35>label35</label35> <spec35>spec35</spec35> <label36>label36</label36> <spec36>spec36</spec36> <label37>label37</label37> <spec37>spec37</spec37> <label38>label38</label38> <spec38>spec38</spec38> <label39>label39</label39> <spec39>spec39</spec39> <label40>label40</label40> <spec40>spec40</spec40> <label41>label41</label41> <spec41>spec41</spec41> <label42>label42</label42> <spec42>spec42</spec42> <label43>label43</label43> <spec43>spec43</spec43> <label44>label44</label44> <spec44>spec44</spec44> <label45>label45</label45> <spec45>spec45</spec45> <label46>label46</label46> <spec46>spec46</spec46> <label47>label47</label47> <spec47>spec47</spec47> <label48>label48</label48> <spec48>spec48</spec48> <label49>label49</label49> <spec49>spec49</spec49> <label50>label50</label50> <spec50>spec50</spec50> <label51>label51</label51> <spec51>spec51</spec51> <label52>label52</label52> <spec52>spec52</spec52> <label53>label53</label53> <spec53>spec53</spec53> <label54>label54</label54> <spec54>spec54</spec54> <label55>label55</label55> <spec55>spec55</spec55> <label56>label56</label56> <spec56>spec56</spec56> <label57>label57</label57> <spec57>spec57</spec57> <label58>label58</label58> <spec58>spec58</spec58> <label59>label59</label59> <spec59>spec59</spec59> <label60>label60</label60> <spec60>spec60</spec60> </header> <data> <item>A12345</item> <category>snacks</category> <label01>a0</label01> <spec01>1</spec01> <label02>b0</label02> <spec02>cereals</spec02> </data> <data> <item>A245678</item> <category>snacks</category> <label01>a0</label01> <spec01>1</spec01> <label02>b0</label02> <spec02>chips</spec02> <label03>q0</label03> <spec03>potato</spec03> <label04>e1</label04> <spec04>fried</spec04> <label05>i1</label05> <spec05>baked</spec05> <label06>p1</label06> <spec06>20g</spec06> </data> </SpecExportOutputFF>我的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>
答案 0 :(得分:0)
只是为了挑战,我找出了你想要做的事情。我认为主要的问题是你正在考虑当务之急,但需要改变思维方式,因为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>