Excel电子表格使用XML和XSLTdynamic单元格着色

我得到了一个XML源文件(来自其他来源)及其各自的XSL文件,以将XML转换为Excel电子表格。

我需要的是根据XML属性为使用XSL的节点dynamic更改电子表格中单元格的背景颜色

例如: Source.XML内容

<workbooks> <Wrkbook <table Id="My table 1"> <Colnames> <ColumnName>Student ID</ColumnName> <ColumnName>Student Name</ColumnName> <ColumnName>Subject 1</ColumnName> <ColumnName>Subject 2</ColumnName> <ColumnName>Subject 3</ColumnName> <ColumnName>Subject 4</ColumnName> <ColumnName>Subject 5</ColumnName> <ColumnName>Subject 6</ColumnName> </Colnames> <Rows> <CI>534</CI> <CI>Ramu</CI> <CI>67</CI> <CI Colour="Green">67</CI> <CI Colour="#e8e9e8">48</CI> <CI>66</CI> <CI Colour="#B3C389">39</CI> <CI>67</CI> </Rows> <Rows> <CI>534</CI> <CI>Raul</CI> <CI Colour="Green">63</CI> <CI>89</CI> <CI Colour="#007788">67</CI> <CI>57</CI> <CI>75</CI> <CI Colour="#AABBCC">92</CI> </Rows> </table> </Wrkbook> </workbooks> 

我之前做的事情是,我曾经在XSL表格中为其各自的XML标签中的属性设置了绿色和Yelow的特定样式,因此我可以pipe理它。 但现在源文件包含颜色代码,我需要基于颜色代码来突出显示。 XSL文件:

 <xsl:template match='/'> <Workbook> <Styles> <Style ss:ID="Green"> <Borders> <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/> <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/> <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/> <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/> </Borders> <Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="11"/> <Interior ss:Color="#CCFFCC" ss:Pattern="Solid"/> </Style> </Styles> <xsl:for-each select='workbooks'> <xsl:for-each select='Wrkbook'> <Worksheet ss:Name='Scores'> <Table x:FullColumns='1' x:FullRows='1'> <xsl:for-each select='table'> <Row> <xsl:for-each select='Colnames/ColumnName'> <Cell ss:StyleID='s41'> <Data ss:Type='String'> <xsl:value-of select='.' disable-output-escaping='yes'/> </Data> </Cell> </xsl:for-each> </Row> <xsl:for-each select='Rows'> <Row> <xsl:for-each select='CI'> <xsl:choose> <xsl:when test="@Colour = 'Green'"> <Cell ss:StyleID='Green'> <Data ss:Type='String'> <xsl:value-of select='.' disable-output-escaping='yes'/> </Data> </Cell> </xsl:when> <xsl:otherwise> <Cell ss:StyleID='s38'> <Data ss:Type='String'> <xsl:value-of select='.' disable-output-escaping='yes'/> </Data> </Cell> </xsl:otherwise> </xsl:choose> </xsl:for-each> </Row> </xsl:for-each> <Row> <Cell></Cell> </Row> </xsl:for-each> </Table> </Worksheet> </xsl:for-each> </xsl:for-each> </Workbook> </xsl:template> 

请忽略XSL中是否有语法错误,只是我正在寻找基于dynamicXML属性高亮显示电子表格颜色。

谢谢!!

使用单个模板而不是嵌套for-each元素要容易得多 。 所以我build议重新组织整个样式表,这样每个模板就可以处理一部分源代码树。 另外,由于必须生成不遵循源树结构的附加数据,因此可以调用具有命名的模板。 我把这个答案分成两部分。 第二部分将试图回答你的问题。

第1部分:重构样式表

在匹配根( / )的模板中,您只需要放置文件的不变基本结构 。 在它里面你可以使用<apply-templates select="*/*/table"/>所以select与你的表中的数据相匹配的模板(跳过workbooksWrkbook )。 由于标题涉及基于颜色的样式的创build,我们稍后将处理它。 所需的<?mso-application progid="Excel.Sheet" ?>处理指令也会生成:

 <xsl:template match='/'> <xsl:processing-instruction name="mso-application">progid="Excel.Sheet"</xsl:processing-instruction> <Workbook> <Styles> <!-- make Style elements for each color here --> </Styles> <Worksheet ss:Name='Scores'> <Table x:FullColumns='1' x:FullRows='1'> <xsl:apply-templates select="*/*/table"/> <!-- will process the rest of the tree --> </Table> </Worksheet> </Workbook> </xsl:template> 

table的模板也很简单。 根据提供的样式表,它包含一个<Row> ,其中包含来自源XML中Colnames/ColumnName元素的数据,每个<Rows>元素包含若干<Row>元素,以及包含空的<Cell> 。 这可以像这样重写:

 <xsl:template match="table"> <Row><xsl:apply-templates select='Colnames/ColumnName'/></Row> <xsl:apply-templates select='Rows'/> <Row><Cell/></Row> </xsl:template> 

两个 <xsl:apply-templates/> 。 第一个将调用模板来构build包含多个ColumnName第一个<Row> 。 第二个将build立单独的数据行。 这是将为每个ColumnName调用的模板:

 <xsl:template match="ColumnName"> <Cell ss:StyleID='s41'> <Data ss:Type='String'> <xsl:value-of select='.' disable-output-escaping='yes'/> </Data> </Cell> </xsl:template> 

这一行将被要求每Rows

 <xsl:template match="Rows"> <Row><xsl:apply-templates select='CI'/></Row> </xsl:template> 

再一次<xsl:aply-templates/> 。 这个将处理每个包含Cell数据的CI元素。 它将不得不从每个元素读取Colour属性,并决定如何渲染它。 目前你只需要区分Green和什么都没有。 我们可以将其改写为:

 <xsl:template match="CI"> <xsl:choose> <xsl:when test="@Colour = 'Green'"> <Cell ss:StyleID='Green'> <xsl:call-template name="print-cell"/> </Cell> </xsl:when> <xsl:otherwise> <Cell ss:StyleID='s38'> <xsl:call-template name="print-cell"/> </Cell> </xsl:otherwise> </xsl:choose> </xsl:template> 

删除重复,并将单元格打印到一个命名模板中,我们使用<xsl:call-template>

 <xsl:template name="print-cell"> <Data ss:Type='String'> <xsl:value-of select='.' disable-output-escaping='yes'/> </Data> </xsl:template> 

第2部分:添加颜色信息

现在样式表被重新组织在较小的模板中,我们可以继续调整它,以便正确读取颜色信息。

首先我们应该制作一个包含所有可用颜色的key

 <xsl:key name="colours" match="CI/@Colour" use="."/> 

这将匹配所有CI元素中的所有Colour属性。 我们可以使用 Colour属性的内容来select它。

在根模板中,我们可以通过为每种颜色构build一个Style元素来构build<Styles>块。 我们将在一个单独的模板中这样做,但首先我们需要在文档中的独特颜色之间进行迭代。 这可以通过在XSLT 1.0中使用Muenchian分组技术来完成(如果您使用的是XSLT 2.0,则可以使用for-each-group以更简单的方式处理此问题):

 <Styles> <xsl:for-each select="//CI/@Colour[count(. | key('colours', .)[1]) = 1]"> <xsl:call-template name="make-style"> <xsl:with-param name="colour" select="."/> </xsl:call-template> </xsl:for-each> </Styles> 

这将调用在源文档中find的每种独特颜色的make-style模板。 使用包含当前颜色的参数colour调用模板。

我们需要每种颜色的ID。 可以使用颜色名称,但ID不能以散列值开始,所以解决问题的一种方法是使用移除#的颜色代码。 您可以使用XPath translate()函数: translate($colour,'#','')

由于您的源数据仍然使用Green ,并且不符合该模式,所以我们必须单独处理。 要设置Style ss:ID属性,我们需要使用原始属性的内容(如果$colourGreen ,否则去掉#

 <xsl:choose> <xsl:when test="$colour = 'Green'"> <xsl:value-of select="$colour"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="translate($colour,'#','')"/> </xsl:otherwise> </xsl:choose> 

我们也必须这样做,build立Interior元素:

 <xsl:choose> <xsl:when test="$colour = 'Green'"> <Interior ss:Color="#CCFFCC" ss:Pattern="Solid"/> </xsl:when> <xsl:otherwise> <Interior ss:Color="{$colour}" ss:Pattern="Solid"/> </xsl:otherwise> </xsl:choose> 

这是最终的make-style模板:

 <xsl:template name="make-style"> <xsl:param name="colour"/> <Style ss:ID="Green"> <xsl:attribute name="ss:ID"> <xsl:choose> <xsl:when test="$colour = 'Green'"> <xsl:value-of select="$colour"></xsl:value-of> </xsl:when> <xsl:otherwise> <xsl:value-of select="translate($colour,'#','')"/> </xsl:otherwise> </xsl:choose> </xsl:attribute> <Borders> <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/> <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/> <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/> <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/> </Borders> <Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="11"/> <xsl:choose> <xsl:when test="$colour = 'Green'"> <Interior ss:Color="#CCFFCC" ss:Pattern="Solid"/> </xsl:when> <xsl:otherwise> <Interior ss:Color="{$colour}" ss:Pattern="Solid"/> </xsl:otherwise> </xsl:choose> </Style> </xsl:template> 

现在我们可以重构CI模板,添加一个xsl:when块来生成一个StyleID为合适颜色的单元格:

  <xsl:template match="CI"> <xsl:choose> <xsl:when test="@Colour = 'Green'"> <Cell ss:StyleID='Green'> <xsl:call-template name="print-cell"/> </Cell> </xsl:when> <xsl:when test="starts-with(@Colour, '#')"> <Cell ss:StyleID="{translate(@Colour,'#','')}"> <xsl:call-template name="print-cell"/> </Cell> </xsl:when> <xsl:otherwise> <Cell ss:StyleID='s38'> <xsl:call-template name="print-cell"/> </Cell> </xsl:otherwise> </xsl:choose> </xsl:template> 

这是最终的样式表。

 <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" version="1.0"> <xsl:output indent="yes"/> <xsl:key name="colours" match="CI/@Colour" use="."/> <xsl:template match='/'> <xsl:processing-instruction name="mso-application">progid="Excel.Sheet"</xsl:processing-instruction> <Workbook> <Styles> <xsl:for-each select="//CI/@Colour[count(. | key('colours', .)[1]) = 1]"> <xsl:call-template name="make-style"> <xsl:with-param name="colour" select="."/> </xsl:call-template> </xsl:for-each> </Styles> <Worksheet ss:Name='Scores'> <Table x:FullColumns='1' x:FullRows='1'> <xsl:apply-templates select="*/*/table"/> </Table> </Worksheet> </Workbook> </xsl:template> <xsl:template match="table"> <Row><xsl:apply-templates select='Colnames/ColumnName'/></Row> <xsl:apply-templates select='Rows'/> <Row><Cell/></Row> </xsl:template> <xsl:template match="ColumnName"> <Cell ss:StyleID='s41'> <Data ss:Type='String'> <xsl:value-of select='.' disable-output-escaping='yes'/> </Data> </Cell> </xsl:template> <xsl:template match="Rows"> <Row><xsl:apply-templates select='CI'/></Row> </xsl:template> <xsl:template name="make-style"> <xsl:param name="colour"/> <Style ss:ID="Green"> <xsl:attribute name="ss:ID"> <xsl:choose> <xsl:when test="$colour = 'Green'"> <xsl:value-of select="$colour"></xsl:value-of> </xsl:when> <xsl:otherwise> <xsl:value-of select="translate($colour,'#','')"/> </xsl:otherwise> </xsl:choose> </xsl:attribute> <Borders> <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1"/> <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1"/> <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1"/> <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1"/> </Borders> <Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="11"/> <xsl:choose> <xsl:when test="$colour = 'Green'"> <Interior ss:Color="#CCFFCC" ss:Pattern="Solid"/> </xsl:when> <xsl:otherwise> <Interior ss:Color="{$colour}" ss:Pattern="Solid"/> </xsl:otherwise> </xsl:choose> </Style> </xsl:template> <xsl:template match="CI"> <xsl:choose> <xsl:when test="@Colour = 'Green'"> <Cell ss:StyleID='Green'> <xsl:call-template name="print-cell"/> </Cell> </xsl:when> <xsl:when test="starts-with(@Colour, '#')"> <Cell ss:StyleID="{translate(@Colour,'#','')}"> <xsl:call-template name="print-cell"/> </Cell> </xsl:when> <xsl:otherwise> <Cell ss:StyleID='s38'> <xsl:call-template name="print-cell"/> </Cell> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="print-cell"> <Data ss:Type='String'> <xsl:value-of select='.' disable-output-escaping='yes'/> </Data> </xsl:template> </xsl:stylesheet> 

您可以看到结果并在此XSLT小提琴中进行调整。