【问题标题】:Converting XML to HTML based on complex elements in the input xml根据输入 xml 中的复杂元素将 XML 转换为 HTML
【发布时间】:2016-01-03 16:17:38
【问题描述】:

我是 XSLT 的新手,我正在尝试将以下 xml 中的数据解析为 html,其中每个 root/Quote/Quotes 是一个 Vehicle,Vehicle 的值是根据相应报价中的 QuoteId 确定的,我需要根据 QuoteID 并排显示 Quote-1 和 Quote-2 和 QuoteID 在 1st <Sequence> 和 2nd <Sequence> 下的相应值,我需要显示所有根/Quotes/Quote 中的所有不同元素它的值,或者如果任何元素或元素的值不存在 - 我需要显示“未找到”

有可能第一个 <Sequence> 可以有 root/Quotes/Quote's 和 <SequenceID> 的 1、2、3 和第二个 <Sequence> 可以有 <SequenceID> 的 1 和 3,在这种情况下我需要将 Quote-2 的所有标签值显示为“未找到”

输入 XML

<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>

期望的输出

<table xmlns:xs="http://www.w3.org/2001/XMLSchema" border="1">
	<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>
		<th class="border-top border-bottom border-left border-right">Quote-1</th>
		<th class="border-top border-bottom border-left border-right">Quote-2</th>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right">Motor</td>
		<td class="border-top border-bottom border-left border-right">Vehicle1</td>
		<td class="border-top border-bottom border-left border-right">Element1</td>
		<td class="border-top border-bottom border-left border-right">122</td>
		<td class="border-top border-bottom border-left border-right">233</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element2</td>
		<td class="border-top border-bottom border-left border-right">233</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element3</td>
		<td class="border-top border-bottom border-left border-right">344</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element4</td>
		<td class="border-top border-bottom border-left border-right">455</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">QuoteID</td>
		<td class="border-top border-bottom border-left border-right">1</td>
		<td class="border-top border-bottom border-left border-right">1</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element7</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element8</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element10</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element11</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element12</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">123</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element13</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element14</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element15</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element16</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right" colspan="count()">Motor</td>
		<td class="border-top border-bottom border-left border-right">Vehicle2</td>
		<td class="border-top border-bottom border-left border-right">Element1</td>
		<td class="border-top border-bottom border-left border-right">466</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element2</td>
		<td class="border-top border-bottom border-left border-right">577</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element3</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element4</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">QuoteID</td>
		<td class="border-top border-bottom border-left border-right">2</td>
		<td class="border-top border-bottom border-left border-right">2</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element7</td>
		<td class="border-top border-bottom border-left border-right">688</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element8</td>
		<td class="border-top border-bottom border-left border-right">799</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element10</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element11</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element12</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element13</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">133</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element14</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">234</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element15</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">456</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element16</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">654</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right" colspan="count()">Motor</td>
		<td class="border-top border-bottom border-left border-right">Vehicle3</td>
		<td class="border-top border-bottom border-left border-right">Element1</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element2</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element3</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element4</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">QuoteID</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element7</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element8</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element10</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element11</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element12</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element13</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">234</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element14</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">443</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element15</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">654</td>
	</tr>
	<tr>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right"></td>
		<td class="border-top border-bottom border-left border-right">Element16</td>
		<td class="border-top border-bottom border-left border-right">Not Found</td>
		<td class="border-top border-bottom border-left border-right">544</td>
	</tr>
</table>

【问题讨论】:

  • 您的问题不清楚。您的输入中没有 。而且很难理解输入到输出的映射——尤其是。当某些值不唯一时。
  • 对不起,我的意思是 QuoteID,如果值存在,我需要所有元素的名称都存在于所有具有值的车辆中,如果不存在,值应该是“未找到”
  • 每个 代表一个事务(命名为 值),每个 Quotes/Quote 代表该事务下的一个 Quote,我的要求是显示 具有的值相同的 在不同的 在 HTML 中并排。提前致谢!

标签: xslt xslt-2.0


【解决方案1】:

您正在将输入中的行转换为输出中的列,并且您正在寻找可能未包含在每个 &lt;Quote&gt; 中的元素。

要管理它,您需要一个所有可能元素名称的列表和&lt;Quotes&gt; 的最大数量。

然后您可以通过position() 循环遍历Quotes 的列表,并从$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>

【讨论】:

  • 感谢您的回复,我应该使用 xslt 2.0,我可以使用 distinct-values() 和 count() 获取完整节点列表和计数,我目前无法显示值,有人可以帮助我提供完整的解决方案。
  • 您仍然可以使用相同的两个模板(match="/" 和 name="outputVehicle")。但是,xslt 2.0 也支持分组,这可能会使其更简单。
  • 而且这个解决方案仍然适用于 xslt-2.0 转换器。
  • 感谢 Rolf 的回复,我已经用 2 个 xslt 制定了解决方案。我将根据需要将其调整为 XSLT 2.0。再次感谢!!
猜你喜欢
  • 2013-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-22
  • 2019-12-11
  • 2015-03-19
相关资源
最近更新 更多