基于输入xml中的复杂元素将XML转换为HTML

时间:2016-01-03 16:17:38

标签: xslt xslt-2.0

我是XSLT的新手,我正在尝试将xml下面的数据解析为html,其中每个根/ Quote / Quotes是一个Vehicle,Vehicle的值是根据相应报价中的QuoteId确定的,我需要显示Quote-1&amp;的相应值。报价-2,QuoteID低于第一<Sequence>&amp;第二个<Sequence>并排基于QuoteID,我需要显示所有根/报价/报价中的所有不同元素及其值,或者是否有任何元素或元素的值不存在 - 我需要显示“未找到”

第一个<Sequence>可能有<SequenceID>的1,2,3和第二个<Sequence>可以拥有{/ 1 / /引号/引号{ {1}} 1&amp; 3,在这种情况下,我需要显示Quote-2的所有标签值为&#39; Not Found&#39;

输入XML

<SequenceID>

所需输出

&#13;
&#13;
<HTMLData>
    <Sequence>
        <QuoteTitle>Quote-1</QuoteTitle>
        <Response>
            <root>
                <Quotes>
                    <Quote>
                        <Element1 value="122"/>
                        <Element2 value="233"/>
                        <Element3 value="344"/>
                        <Element4 value="455"/>
                        <QuoteID value="1"/>
                    </Quote>
                </Quotes>
                <Quotes>
                    <Quote>
                        <Element1 value="466"/>
                        <Element2 value="577"/>
                        <Element7 value="688"/>
                        <Element8 value="799"/>
                        <QuoteID value="2"/>
                    </Quote>
                </Quotes>
            </root>
        </Response>
    </Sequence>
    <Sequence>
        <QuoteTitle>Quote-2</QuoteTitle>
        <Response>
            <root>
                <Quotes>
                    <Quote>
                        <Element1 value="233"/>
                        <Element10 value=""/>
                        <Element11 value=""/>
                        <Element12 value="123"/>
                        <QuoteID value="1"/>
                    </Quote>
                </Quotes>
                <Quotes>
                    <Quote>
                        <Element13 value="123"/>
                        <Element14 value="234"/>
                        <Element15 value="456"/>
                        <QuoteID value="2"/>
                        <Element16 value="654"/>
                    </Quote>
                </Quotes>
                <Quotes>
                    <Quote>
                        <Element13 value="234"/>
                        <Element14 value="443"/>
                        <Element15 value="654"/>
                        <Element16 value="544"/>
                        <QuoteID value="3"/>
                    </Quote>
                </Quotes>
            </root>
        </Response>
    </Sequence>
</HTMLData>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:0)

您正在将输入中的行转换为输出中的列,并且您正在查找可能未包含在每个<Quote>中的元素。

要对此进行管理,您需要列出所有可能的元素名称和<Quotes>的最大数量。

然后,您可以按Quotes循环查看position()列表,并查找$elements列表中的所有元素。

完整的解决方案:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="exsl"
    version="1.0">

    <xsl:output method="html"/>

    <xsl:key name="element-key" match="//root/Quotes/Quote/*" use="name()" />

    <!-- collect all posible element-names -->
    <xsl:variable name="elements">
        <xsl:for-each select="//root/Quotes/Quote/*">
            <xsl:if test="generate-id() = generate-id(key('element-key', name())[1])">
                <xsl:apply-templates mode="elements" select="."/>
            </xsl:if>
        </xsl:for-each>
    </xsl:variable>

    <xsl:template match="Quote/*" mode="elements">
        <element>
            <xsl:attribute name="name"><xsl:value-of select="name()"/></xsl:attribute>
        </element>
    </xsl:template>

    <xsl:variable name="vehicleCount">
        <xsl:call-template name="vehicleCount">
            <xsl:with-param name="nodelist" select="//root"></xsl:with-param>
        </xsl:call-template>
    </xsl:variable>

    <xsl:template name="vehicleCount">
        <xsl:param name="nodelist" />

        <xsl:choose>
            <xsl:when test="count($nodelist) > 0">
                <xsl:variable name="countFirst" select="count(exsl:node-set($nodelist[1])/Quotes)"/>
                <xsl:variable name="maxRest">
                    <xsl:call-template name="vehicleCount">
                        <xsl:with-param name="nodelist" select="exsl:node-set($nodelist[position()>1])" />
                    </xsl:call-template> 
                </xsl:variable>
                <xsl:choose>
                    <xsl:when test="$countFirst > $maxRest"><xsl:value-of select="$countFirst"/></xsl:when>
                    <xsl:otherwise><xsl:value-of select="$maxRest"/></xsl:otherwise>
                </xsl:choose>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="0"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:variable name="quoteTitles">
        <xsl:copy-of select="/HTMLData/Sequence/QuoteTitle"/>
    </xsl:variable>

    <xsl:variable name="sequences">
        <xsl:copy-of select="/HTMLData/Sequence"/>
    </xsl:variable>

    <xsl:template match="/">
        <table>
            <tr>
                <th class="border-top border-bottom border-left border-right">Type</th>
                <th class="border-top border-bottom border-left border-right">Vehicle</th>
                <th class="border-top border-bottom border-left border-right">Label</th>
                <xsl:for-each select="exsl:node-set($quoteTitles)/*">
                    <th class="border-top border-bottom border-left border-right"><xsl:value-of select="text()"/></th>
                </xsl:for-each>
            </tr>
            <xsl:call-template name="outputVehicle"/>
        </table>
    </xsl:template>

    <xsl:template name="outputVehicle">
        <xsl:param name="pos">1</xsl:param>

        <xsl:for-each select="exsl:node-set($elements)/*">
            <xsl:variable name="elementName" select="@name"/>
            <tr>
                <xsl:choose>
                    <xsl:when test="$elementName = exsl:node-set($elements)/*[1]/@name">
                        <td class="border-top border-bottom border-left border-right">Motor</td>
                        <td class="border-top border-bottom border-left border-right">Vehicle<xsl:value-of select="$pos"/></td>
                    </xsl:when>
                    <xsl:otherwise>
                        <td class="border-top border-bottom border-left border-right"></td>
                        <td class="border-top border-bottom border-left border-right"></td>
                    </xsl:otherwise>
                </xsl:choose>
                <td class="border-top border-bottom border-left border-right"><xsl:value-of select="$elementName"/></td>
                <xsl:for-each select="exsl:node-set($quoteTitles)/*">
                    <xsl:variable name="quoteTitle" select="text()"/>
                    <xsl:variable name="quote" select="exsl:node-set($sequences)/*[QuoteTitle=$quoteTitle]/Response/root/Quotes[position()=$pos]/Quote/*[name()=$elementName]/@value" />
                    <td class="border-top border-bottom border-left border-right">
                        <xsl:choose>
                            <xsl:when test="$quote"><xsl:value-of select="$quote"/></xsl:when>
                            <xsl:otherwise>Not Found</xsl:otherwise>
                        </xsl:choose>
                    </td>            
                </xsl:for-each>
            </tr>        
        </xsl:for-each>


        <xsl:if test="$pos &lt; $vehicleCount">
            <!-- wonder if xslt-processors are able to do tail-call optimization... -->
            <xsl:call-template name="outputVehicle"><xsl:with-param name="pos" select="$pos+1" /></xsl:call-template>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>