将XML文件转换为CSV,记录总数和合并的几列

ryevplcw  于 2023-02-06  发布在  其他
关注(0)|答案(1)|浏览(133)

我们需要将XML文件转换为csv,并在尾部添加总记录计数,并将XML文件中的一些列添加到一列中。
通过使用XSLT,我能够在Trailer记录中实现总行数,但没有找到将几列合并为一列的方法。我是XSLT新手,真的希望有人能帮助我。
请查看以下示例以了解更多详细信息。
输入xml文件

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns1:getDocumentByKeyResponse xmlns:ns1="http://www.taleo.com/ws/integration/toolkit/2005/07">
         <Document xmlns="http://www.taleo.com/ws/integration/toolkit/2005/07">
            <Attributes>
               <Attribute name="count">137</Attribute>
               <Attribute name="duration">0:00:04.625</Attribute>
               <Attribute name="entity">Requisition</Attribute>
               <Attribute name="mode">XML</Attribute>
               <Attribute name="version">http://www.taleo.com/ws/tee800/2009/01</Attribute>
            </Attributes>
            <Content>
               <ExportXML>
                  <record>
                     <field name="position_id">1110684</field>
                     <field name="status">Approved</field>
                     <field name="number_of_openings">14</field>
                     <field name="Internal_Description1">test</field>
                     <field name="Internal_Description2">test1</field>
                     <field name="Internal_Description3">test2</field>
                     <field name="Internal_Description4" />
                     <field name="Internal_Description5" />
                     <field name="Description1">test5</field>
                     <field name="Description2">test6</field>
                     <field name="Description3">test7</field>
                     <field name="Description4" />
                     <field name="Description5" />
                     <field name="Req_Creation_Date">2011-08-31 11:54:07</field>
                     <field name="Req_Last_Modified_Date">2022-09-02 13:44:07</field>
                  </record>
                  <record>
                     <field name="position_id">1110684</field>
                     <field name="status">Approved</field>
                     <field name="number_of_openings">14</field>
                     <field name="Internal_Description1">test</field>
                     <field name="Internal_Description2">test1</field>
                     <field name="Internal_Description3">test2</field>
                     <field name="Internal_Description4" />
                     <field name="Internal_Description5" />
                     <field name="Description1">test5</field>
                     <field name="Description2">test6</field>
                     <field name="Description3">test7</field>
                     <field name="Description4" />
                     <field name="Description5" />
                     <field name="Req_Creation_Date">2011-08-31 11:54:07</field>
                     <field name="Req_Last_Modified_Date">2022-09-02 13:44:07</field>
                  </record>
               </ExportXML>
            </Content>
         </Document>
      </ns1:getDocumentByKeyResponse>
   </soap:Body>
</soap:Envelope>

预期产出

position_id~status~number_of_openings~Internal_Description~Description~Req_Creation_Date~Req_Last_Modified_Date
1110684~Approved~14~test test1 test3~test5 test6 test7~2011-08-31 11:54:07~2022-09-02 13:44:07
1110684~Approved~14~test test1 test3~test5 test6 test7~2011-08-31 11:54:07~2022-09-02 13:44:07
T~2

其中

  • Internal_Description是列的组合:内部描述1、内部描述2、内部描述3、内部描述4、内部描述5
  • 说明列是以下内容的组合:描述1、描述2、描述3、描述4、描述5

下面是我用于转换的XSLT代码,但没有找到组合列的方法。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fct="http://www.taleo.com/xsl_functions" xmlns:itk="http://www.taleo.com/ws/integration/toolkit/2005/07" xmlns:quer="http://www.taleo.com/ws/integration/query" version="2.0">
   <xsl:output method="text" encoding="UTF-8" />
   <xsl:param name="csvDelimiter">~</xsl:param>
   <xsl:param name="csvQuoteCharacter">"</xsl:param>
   <xsl:param name="requestFile" />

   <!-- ======================================= -->
   <!-- Root template. -->
   <!-- ======================================= -->
   <xsl:template match="/">
      <!-- Build header row from request file. -->
      <xsl:for-each select="document(replace($requestFile, '\\', '/'))/quer:query/quer:projections/quer:projection">
         <xsl:choose>
            <xsl:when test="@alias">
               <xsl:value-of select="@alias" />
            </xsl:when>
            <xsl:otherwise>
               <xsl:value-of select="fct:quote(quer:field/@path)" />
            </xsl:otherwise>
         </xsl:choose>
         <xsl:if test="position() != last()">
            <xsl:value-of select="$csvDelimiter" />
         </xsl:if>
      </xsl:for-each>
      <xsl:text />
      <!-- Process records. -->
      <xsl:apply-templates select="//itk:record" />
      <!-- Build trailer record. -->
      <xsl:value-of select="$csvQuoteCharacter" />
      <xsl:text>T</xsl:text>
      <xsl:value-of select="$csvQuoteCharacter" />
      <xsl:value-of select="$csvDelimiter" />
      <xsl:value-of select="$csvQuoteCharacter" />
      <xsl:value-of select="format-number(count(//itk:record), '000000000')" />
      <xsl:value-of select="$csvQuoteCharacter" />
      <xsl:text />
   </xsl:template>

   <!-- ======================================= -->
   <!-- Template matching each record. -->
   <!-- ======================================= -->
   <xsl:template match="itk:record">
      <xsl:for-each select="itk:field">
         <xsl:value-of select="fct:quote(.)" />
         <xsl:if test="position() != last()">
            <xsl:value-of select="$csvDelimiter" />
         </xsl:if>
      </xsl:for-each>
      <xsl:text />
   </xsl:template>

   <!-- ======================================= -->
   <!-- Quote a value if it contains the csvDelimiter or the csvQuoteCharacter. -->
   <!-- ======================================= -->
   <xsl:function name="fct:quote">
      <xsl:param name="value" />
      <xsl:choose>
         <xsl:when test="contains($value, $csvDelimiter) or contains($value, $csvQuoteCharacter)">
            <xsl:value-of select="replace($value, $csvQuoteCharacter, concat($csvQuoteCharacter, $csvQuoteCharacter))" />
         </xsl:when>
         <xsl:otherwise>
            <xsl:value-of select="$value" />
         </xsl:otherwise>
      </xsl:choose>
   </xsl:function>

   <xsl:function name="fct:nvl">
      <xsl:param name="value" />
      <xsl:param name="replace-with" />
      <xsl:choose>
         <xsl:when test="string-length($value) &gt; 0">
            <xsl:value-of select="$value" />
         </xsl:when>
         <xsl:otherwise>
            <xsl:value-of select="$replace-with" />
         </xsl:otherwise>
      </xsl:choose>
   </xsl:function>

</xsl:stylesheet>
yqyhoc1h

yqyhoc1h1#

如果使用XSLT 2.0,请考虑for-each-group,其中Map了所有@name值,但没有标头的后缀号,并再次Map了记录,其中字符串连接了所有组值:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:fct="http://www.taleo.com/xsl_functions" 
                xmlns:itk="http://www.taleo.com/ws/integration/toolkit/2005/07"
                xmlns:quer="http://www.taleo.com/ws/integration/query" 
                version="2.0">
   <xsl:output method="text" encoding="UTF-8" />
   <xsl:param name="csvDelimiter">~</xsl:param>
   <xsl:param name="csvQuoteCharacter">"</xsl:param>
   <xsl:param name="requestFile" />
   <xsl:param name="lineBreak"><xsl:text>&#xa;</xsl:text></xsl:param>

   <!-- ======================================= -->
   <!-- Root template. -->
   <!-- ======================================= -->
   <xsl:template match="/">
      <!-- Build header from @name without number suffixes -->
      <xsl:for-each-group select="//itk:field" group-by="replace(@name, '[0-9]', '')">
         <xsl:value-of select="current-grouping-key()" />
         <xsl:value-of select="if (position() != last()) then $csvDelimiter else $lineBreak" />
      </xsl:for-each-group>
      
      <xsl:text />
      <!-- Process records. -->
      <xsl:apply-templates select="//itk:record" />
      <!-- Build trailer record. -->
      <xsl:value-of select="$csvQuoteCharacter" />
      <xsl:text>T</xsl:text>
      <xsl:value-of select="$csvQuoteCharacter" />
      <xsl:value-of select="$csvDelimiter" />
      <xsl:value-of select="$csvQuoteCharacter" />
      <xsl:value-of select="format-number(count(//itk:record), '000000000')" />
      <xsl:value-of select="$csvQuoteCharacter" />
      <xsl:text />
   </xsl:template>

   <!-- ======================================= -->
   <!-- Template matching each record. -->
   <!-- ======================================= -->
   <xsl:template match="itk:record">
     <!-- Map through @name groups without number suffixes -->
      <xsl:for-each-group select="itk:field" group-by="replace(@name, '[0-9]', '')">
        <!-- String join all group values -->
         <xsl:variable name="val">
           <xsl:value-of select="current-group()" separator=" "/>
         </xsl:variable>
         <!-- Trim whitespace and pass into function-->
         <xsl:value-of select="normalize-space(fct:quote($val))" />
         <xsl:value-of select="if (position() != last()) then $csvDelimiter else $lineBreak" />
      </xsl:for-each-group>
      <xsl:text />
   </xsl:template>

   <!-- ======================================= -->
   <!-- Quote a value if it contains the csvDelimiter or the csvQuoteCharacter. -->
   <!-- ======================================= -->
   <xsl:function name="fct:quote">
      <xsl:param name="value" />
      <xsl:choose>
         <xsl:when test="contains($value, $csvDelimiter) or contains($value, $csvQuoteCharacter)">
            <xsl:value-of select="replace($value, $csvQuoteCharacter, concat($csvQuoteCharacter, $csvQuoteCharacter))" />
         </xsl:when>
         <xsl:otherwise>
            <xsl:value-of select="$value" />
         </xsl:otherwise>
      </xsl:choose>
   </xsl:function>

   <xsl:function name="fct:nvl">
      <xsl:param name="value" />
      <xsl:param name="replace-with" />
      <xsl:choose>
         <xsl:when test="string-length($value) &gt; 0">
            <xsl:value-of select="$value" />
         </xsl:when>
         <xsl:otherwise>
            <xsl:value-of select="$replace-with" />
         </xsl:otherwise>
      </xsl:choose>
   </xsl:function>

</xsl:stylesheet>

Online Demo

产出

position_id~status~number_of_openings~Internal_Description~Description~Req_Creation_Date~Req_Last_Modified_Date
1110684~Approved~14~test test1 test2~test5 test6 test7~2011-08-31 11:54:07~2022-09-02 13:44:07
1110684~Approved~14~test test1 test2~test5 test6 test7~2011-08-31 11:54:07~2022-09-02 13:44:07
"T"~"000000002"

相关问题