1

我正在尝试将从 Excel 导出的 XML 结构转换为具有嵌套元素的新结构。我很难弄清楚如何使用 XSLT v1.0 做到这一点。

我的目标是将行数据放入结果 xml 的所需级别。因此,如果一行仅包含 1 个包含数据的单元格,则它是一个类别,例如:

<projects> 
<category name="001">
...
</category>
</projects>

如果一行有 2 个数据单元格,则它代表一个区域,应该是 previos 类别的子级。

<projects> 
<category name="001">
<region name="AAA">...</region>
<region name="BBB">...</region>
</category>
</projects>

如果该行有 3 或 4 个包含数据的单元格,则它表示一个帐户,该帐户应该是前一个区域的子级。

<projects> 
<category name="001">
<region name="AAA">
<account name="lorem">...</account>
<account name="ipsum">...</account>
</region>
<region name="BBB">...</region>
...
</category>
</projects>

好的,到目前为止我所拥有的:这是来自 Excel 的 XML 文件。它具有简单的结构,具有重复的行元素。每行包含 5 个单元格,但并非每个单元格都始终包含一个 Data 元素。我试图用它来确定每行代表什么样的信息。

    <Table ss:ExpandedColumnCount="6" ss:ExpandedRowCount="69" x:FullColumns="1"    x:FullRows="1" ss:StyleID="s62" ss:DefaultColumnWidth="69">
   <Row ss:AutoFitHeight="0" ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s68"/>
    <Cell ss:StyleID="s69"/>
    <Cell ss:StyleID="s68"/>
    <Cell ss:StyleID="s68"/>
    <Cell ss:StyleID="s68"/>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="15">
    <Cell ss:Index="2" ss:StyleID="s70"><Data ss:Type="String">Categorie 004</Data></Cell>
    <Cell ss:StyleID="s71"/>
    <Cell ss:StyleID="s70"/>
    <Cell ss:StyleID="s72"/>
    <Cell ss:StyleID="s70"/>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s68"><Data ss:Type="String">AAA</Data></Cell>
    <Cell ss:StyleID="s69"/>
    <Cell ss:StyleID="s69"><Data ss:Type="String">X</Data></Cell>
    <Cell ss:StyleID="s73"/>
    <Cell ss:StyleID="s74"><Data ss:Type="Number">0.01</Data></Cell>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s68"/>
    <Cell ss:StyleID="s69"/>
    <Cell ss:StyleID="s68"/>
    <Cell ss:StyleID="s73"/>
    <Cell ss:StyleID="s68"/>
   </Row>
   <Row ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s68"/>
    <Cell ss:StyleID="s69"/>
    <Cell ss:StyleID="s68"/>
    <Cell ss:StyleID="s73"/>
    <Cell ss:StyleID="s68"/>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s68"/>
    <Cell ss:StyleID="s69"/>
    <Cell ss:StyleID="s68"/>
    <Cell ss:StyleID="s73"/>
    <Cell ss:StyleID="s68"/>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="15">
    <Cell ss:Index="2" ss:StyleID="s70"><Data ss:Type="String">Categorie 001</Data></Cell>
    <Cell ss:StyleID="s71"/>
    <Cell ss:StyleID="s70"/>
    <Cell ss:StyleID="s72"/>
    <Cell ss:StyleID="s70"/>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s82"><Data ss:Type="String">AAA</Data></Cell>
    <Cell ss:StyleID="s83"/>
    <Cell ss:StyleID="s82"/>
    <Cell ss:StyleID="s84"/>
    <Cell ss:StyleID="s85"><Data ss:Type="Number">3.0800000000000001E-2</Data></Cell>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s68"><Data ss:Type="String">dolor</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="Number">123</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="String">A</Data></Cell>
    <Cell ss:StyleID="s86"/>
    <Cell ss:StyleID="s74"><Data ss:Type="Number">0.01</Data></Cell>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="15">
    <Cell ss:Index="2" ss:StyleID="s68"><Data ss:Type="String">sit amet</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="Number">445</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="String">B</Data></Cell>
    <Cell ss:StyleID="s86"/>
    <Cell ss:StyleID="s74"><Data ss:Type="Number">0.03</Data></Cell>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s68"><Data ss:Type="String">consetetur</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="Number">36</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="String">B</Data></Cell>
    <Cell ss:StyleID="s86"/>
    <Cell ss:StyleID="s74"><Data ss:Type="Number">8.0000000000000004E-4</Data></Cell>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s82"><Data ss:Type="String">BBB</Data></Cell>
    <Cell ss:StyleID="s83"/>
    <Cell ss:StyleID="s82"/>
    <Cell ss:StyleID="s84"/>
    <Cell ss:StyleID="s85"><Data ss:Type="Number">0.03</Data></Cell>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s68"><Data ss:Type="String">sadipscing</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="Number">666</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="String">A</Data></Cell>
    <Cell ss:StyleID="s86"/>
    <Cell ss:StyleID="s74"><Data ss:Type="Number">0.01</Data></Cell>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="15">
    <Cell ss:Index="2" ss:StyleID="s68"><Data ss:Type="String">elitr</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="Number">97</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="String">C</Data></Cell>
    <Cell ss:StyleID="s86"/>
    <Cell ss:StyleID="s74"><Data ss:Type="Number">0.02</Data></Cell>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="15">
    <Cell ss:Index="2" ss:StyleID="s68"/>
    <Cell ss:StyleID="s69"/>
    <Cell ss:StyleID="s68"/>
    <Cell ss:StyleID="s73"/>
    <Cell ss:StyleID="s68"/>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s70"><Data ss:Type="String">Categorie 001</Data></Cell>
    <Cell ss:StyleID="s71"/>
    <Cell ss:StyleID="s70"/>
    <Cell ss:StyleID="s72"/>
    <Cell ss:StyleID="s70"/>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s82"><Data ss:Type="String">AAA</Data></Cell>
    <Cell ss:StyleID="s83"/>
    <Cell ss:StyleID="s82"/>
    <Cell ss:StyleID="s84"/>
    <Cell ss:StyleID="s85"><Data ss:Type="Number">0.04</Data></Cell>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s68"><Data ss:Type="String">aliquyam</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="Number">65</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="String">A</Data></Cell>
    <Cell ss:StyleID="s86"/>
    <Cell ss:StyleID="s74"><Data ss:Type="Number">0.02</Data></Cell>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s68"><Data ss:Type="String">ipsum</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="Number">99</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="String">B</Data></Cell>
    <Cell ss:StyleID="s86"/>
    <Cell ss:StyleID="s74"><Data ss:Type="Number">0.02</Data></Cell>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s82"><Data ss:Type="String">BBB</Data></Cell>
    <Cell ss:StyleID="s83"/>
    <Cell ss:StyleID="s82"/>
    <Cell ss:StyleID="s84"/>
    <Cell ss:StyleID="s85"><Data ss:Type="Number">0.01</Data></Cell>
   </Row>
   <Row ss:AutoFitHeight="0" ss:Height="14.25">
    <Cell ss:Index="2" ss:StyleID="s68"><Data ss:Type="String">lorem</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="Number">321</Data></Cell>
    <Cell ss:StyleID="s69"><Data ss:Type="String">C</Data></Cell>
    <Cell ss:StyleID="s86"/>
    <Cell ss:StyleID="s74"><Data ss:Type="Number">0.01</Data></Cell>
   </Row>
  </Table>

到目前为止,我已经创建了以下样式表,并且能够根据需要过滤所有信息。

<!-- Filter Excel Cells -->
<xsl:template match="ss:Row">
    <xsl:if test="count(.//ss:Data) &gt; 0">
        <xsl:choose>
            <xsl:when test="count(.//ss:Data)=1">
                <Categorie>
                    <xsl:value-of select=".//ss:Cell[1]/ss:Data"/>
                </Categorie>
            </xsl:when>
            <xsl:when test="count(.//ss:Data)=2">
                <Region>
                    <xsl:value-of select=".//ss:Cell[1]/ss:Data"/>
                </Region>
            </xsl:when>
            <xsl:when test="count(.//ss:Data)=3">
                <xsl:choose>
                    <xsl:when test=".//ss:Cell[5]/ss:Data='Rating'">
                        <Header>
                            <Text1>
                                <xsl:value-of select=".//ss:Cell[1]/ss:Data"/>
                            </Text1>
                            <Text2>
                                <xsl:value-of select=".//ss:Cell[3]/ss:Data"/>
                            </Text2>
                            <Text3>
                                <xsl:value-of select=".//ss:Cell[5]/ss:Data"/>
                            </Text3>
                        </Header>
                    </xsl:when>
                    <xsl:otherwise>
                        <Account>
                            <Name>
                                <xsl:value-of select=".//ss:Cell[1]/ss:Data"/>
                            </Name>
                            <Value>
                                <xsl:value-of select=".//ss:Cell[3]/ss:Data"/>
                            </Value>
                            <Rating>
                                <xsl:value-of select=".//ss:Cell[5]/ss:Data"/>
                            </Rating>
                        </Account>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:when>
            <xsl:when test="count(.//ss:Data)=4">
                <xsl:choose>
                    <xsl:when test=".//ss:Cell[5]/ss:Data='Gewicht'">
                        <Header>
                            <Text1>
                                <xsl:value-of select=".//ss:Cell[1]/ss:Data"/>
                            </Text1>
                            <Text2>
                                <xsl:value-of select=".//ss:Cell[2]/ss:Data"/>
                            </Text2>
                            <Text3>
                                <xsl:value-of select=".//ss:Cell[3]/ss:Data"/>
                            </Text3>
                            <Text4>
                                <xsl:value-of select=".//ss:Cell[5]/ss:Data"/>
                            </Text4>
                        </Header>
                    </xsl:when>
                    <xsl:otherwise>
                        <Account>
                            <Name>
                                <xsl:value-of select=".//ss:Cell[1]/ss:Data"/>
                            </Name>
                            <Type>
                                <xsl:value-of select=".//ss:Cell[2]/ss:Data"/>
                            </Type>
                            <Value>
                                <xsl:value-of select=".//ss:Cell[3]/ss:Data"/>
                            </Value>
                            <Rating>
                                <xsl:value-of select=".//ss:Cell[5]/ss:Data"/>
                            </Rating>
                        </Account>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:when>
        </xsl:choose>
    </xsl:if>
</xsl:template>

我的结果现在看起来是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<Projects xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
    <Categorie>Categorie 004</Categorie>
    <Region>AAA</Region>
    <Account>
        <Name>AAA</Name>
        <Value>X</Value>
        <Rating>0.01</Rating>
    </Account>
    <Account>
        <Name>Name</Name>
        <Type>Value</Type>
        <Value>Type</Value>
        <Rating>Rating</Rating>
    </Account>
    <Categorie>Categorie 001</Categorie>
    <Region>AAA</Region>
    <Account>
        <Name>dolor</Name>
        <Type>123</Type>
        <Value>A</Value>
        <Rating>0.01</Rating>
    </Account>
    <Account>
        <Name>sit amet</Name>
        <Type>445</Type>
        <Value>B</Value>
        <Rating>0.03</Rating>
    </Account>
    <Account>
        <Name>consetetur</Name>
        <Type>36</Type>
        <Value>B</Value>
        <Rating>8.0000000000000004E-4</Rating>
    </Account>
    <Region>BBB</Region>
    <Account>
        <Name>sadipscing</Name>
        <Type>666</Type>
        <Value>A</Value>
        <Rating>0.01</Rating>
    </Account>
    <Account>
        <Name>elitr</Name>
        <Type>97</Type>
        <Value>C</Value>
        <Rating>0.02</Rating>
    </Account>
    <Account>
        <Name>Name</Name>
        <Type>Value</Type>
        <Value>Type</Value>
        <Rating>Rating</Rating>
    </Account>
    <Categorie>Categorie 001</Categorie>
    <Region>AAA</Region>
    <Account>
        <Name>aliquyam</Name>
        <Type>65</Type>
        <Value>A</Value>
        <Rating>0.02</Rating>
    </Account>
    <Account>
        <Name>ipsum</Name>
        <Type>99</Type>
        <Value>B</Value>
        <Rating>0.02</Rating>
    </Account>
    <Region>BBB</Region>
    <Account>
        <Name>lorem</Name>
        <Type>321</Type>
        <Value>C</Value>
        <Rating>0.01</Rating>
    </Account>
</Projects>

不错(对我来说),但我需要像这样嵌套数据,而不是每个数据都在同一级别。我需要你的帮助!

<?xml version="1.0" encoding="UTF-8"?>
<Projects xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
    <Categorie name="001"/>
        <Region name="AAA">
            <Account>
                <Name>Name</Name>
                <Type>Value</Type>
                <Value>Type</Value>
                <Rating>Rating</Rating>
            </Account>
            <Account>
                <Name>Name</Name>
                <Type>Value</Type>
                <Value>Type</Value>
                <Rating>Rating</Rating>
            </Account>
        </Region>
        <Region name="BBB">
            <Account>
                <Name>Name</Name>
                <Type>Value</Type>
                <Value>Type</Value>
                <Rating>Rating</Rating>
            </Account>
            <Account>
                <Name>Name</Name>
                <Type>Value</Type>
                <Value>Type</Value>
                <Rating>Rating</Rating>
            </Account>
            ...
        </Region>
        <Categorie name="002"/>
            <Region name="AAA">
                ...
            </Region>
        </Categorie>
</Projects>
4

2 回答 2

0

我相信您需要在某些标签上使用元素/属性调用,以将它们置于您需要的格式中,如下所示

<xsl:element name="Categorie">
        <xsl:attribute name="name">
                 <xsl:value-of select=".//ss:Cell[1]/ss:Data"/>
        </xsl:attribute>
        <xsl:element name="Region">
            <xsl:attribute name="name">
                 <xsl:value-of select=".//ss:Cell[1]/ss:Data"/>
            </xsl:attribute>
          //rest of transform here
        </xsl:element>      
 </xsl:element>

我还没有对此进行任何类型的测试,但这应该为您指明所需的方向

于 2014-02-25T12:39:07.660 回答
0

将一维标记转换为层次结构是一个分组问题。在这种情况下有group-starting-with问题。

在 XSLT 2.0 中

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:template match="Table">
        <xsl:for-each-group 
            select="Row[.//Data]" 
            group-starting-with="Row[count(.//Data)=1]">
            <Categorie>
                <xsl:for-each-group 
                    select="current-group()[position()>1]" 
                    group-starting-with="Row[count(.//Data)=2]">
                    <xsl:choose>
                        <xsl:when test="not(self::Row[count(.//Data)=2])">
                            <xsl:apply-templates select="current-group()"/>
                        </xsl:when>
                        <xsl:otherwise>
                            <Region>
                                <xsl:apply-templates 
                                    select="current-group()[position()>1]"/>
                            </Region>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:for-each-group>
            </Categorie>
        </xsl:for-each-group>
    </xsl:template>

   <xsl:template match="Row">
        <Account>
            <xsl:apply-templates/>
        </Account>
    </xsl:template>

    <xsl:template match="Row[.//Cell[5]/Data[.='Rating' or .='Gewicht']]">
        <Header>
            <xsl:apply-templates/>
        </Header>
    </xsl:template>

    <xsl:template match="Data">
        <Data>
            <xsl:value-of select="."/>
        </Data>
    </xsl:template>    
</xsl:stylesheet>

输出:

<Categorie>
   <Account>
      <Data>AAA</Data>
      <Data>X</Data>
      <Data>0.01</Data>
   </Account>
</Categorie>
<Categorie>
   <Region>
      <Account>
         <Data>dolor</Data>
         <Data>123</Data>
         <Data>A</Data>
         <Data>0.01</Data>
      </Account>
      <Account>
         <Data>sit amet</Data>
         <Data>445</Data>
         <Data>B</Data>
         <Data>0.03</Data>
      </Account>
      <Account>
         <Data>consetetur</Data>
         <Data>36</Data>
         <Data>B</Data>
         <Data>8.0000000000000004E-4</Data>
      </Account>
   </Region>
   <Region>
      <Account>
         <Data>sadipscing</Data>
         <Data>666</Data>
         <Data>A</Data>
         <Data>0.01</Data>
      </Account>
      <Account>
         <Data>elitr</Data>
         <Data>97</Data>
         <Data>C</Data>
         <Data>0.02</Data>
      </Account>
   </Region>
</Categorie>
<Categorie>
   <Region>
      <Account>
         <Data>aliquyam</Data>
         <Data>65</Data>
         <Data>A</Data>
         <Data>0.02</Data>
      </Account>
      <Account>
         <Data>ipsum</Data>
         <Data>99</Data>
         <Data>B</Data>
         <Data>0.02</Data>
      </Account>
   </Region>
   <Region>
      <Account>
         <Data>lorem</Data>
         <Data>321</Data>
         <Data>C</Data>
         <Data>0.01</Data>
      </Account>
   </Region>
</Categorie>

请注意:您的输入缺少名称空间声明xss前缀(即 xmlns:x="ns1" xmlns:ss="ns2")。此外,当使用起始模式分组时,匹配的元素是组的一部分(因此current-group()[position()>1]),并且可能存在第一个组,其中包含第一次匹配之前的所有元素(因此xsl:choose)。Data为了更好地理解主要问题,省略了元素的转换。

于 2019-07-27T16:47:37.670 回答