簡體   English   中英

將XML文件轉換為CSV

[英]Convert XML file to CSV

在使用正則表達式轉換了混亂的XML之后,我現在需要再次更改它。 這個源文件

<product>
    <sku>SP00001</sku>
    <PID_OWNER_SellerID>StoreName</PID_OWNER_SellerID>
    <EANCode>8711983489813</EANCode>
    <DeliveryDays>2</DeliveryDays>
</product>

必須成為CSV文件,但是像這樣:

sku        field                 value
SP00001    PID_OWNER_SellerID    StoreName
SP00001    EANCode               8711983489813
SP00001    DeliveryDays          2

我認為這超出了regex的范圍,必須使用XSL完成嗎?

嘗試使用正則表達式解析XML通常是一個壞主意,因為存在一種無限的方式來格式化結構上相同的XML文檔,但是會簡化您的正則表達式。

對於體積不大的文件,一定要使用XSL,記住要指定“文本”作為輸出方法。 不要忘記,如果需要,您可以通過編程方式調用XSL流程-大多數語言都允許您這樣做。

對於大文件,請考慮編寫一個使用流API(例如SAX或推送分析器API之一)的小程序。

這是一些適合您的XSLT ...

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
                exclude-result-prefixes="msxsl"
    >
  <xsl:output method="text" indent="yes"/>

  <xsl:template match="/">
    <xsl:call-template name="headerRow" />
    <xsl:apply-templates select="//product" />
  </xsl:template>

  <xsl:template name="headerRow">
    <xsl:call-template name="rightpad">
      <xsl:with-param name="fieldvalue" select="'sku'"/>
      <xsl:with-param name="fieldsize" select="number(11)"/>
    </xsl:call-template>

    <xsl:call-template name="rightpad">
      <xsl:with-param name="fieldvalue" select="'field'"/>
      <xsl:with-param name="fieldsize" select="number(22)"/>
    </xsl:call-template>

    <xsl:text>value&#xd;&#xa;</xsl:text>
  </xsl:template>

  <xsl:template match="product">
    <xsl:for-each select="node()[local-name(.) != 'sku']">

      <xsl:call-template name="rightpad">
        <xsl:with-param name="fieldvalue" select="../sku"/>
        <xsl:with-param name="fieldsize" select="number(11)"/>
      </xsl:call-template>

      <xsl:call-template name="rightpad">
        <xsl:with-param name="fieldvalue" select="local-name(.)"/>
        <xsl:with-param name="fieldsize" select="number(22)"/>
      </xsl:call-template>

      <xsl:value-of select="."/>
      <xsl:text>&#xd;&#xa;</xsl:text>
    </xsl:for-each>
  </xsl:template>

  <xsl:template name="rightpad">
    <xsl:param name="fieldvalue" select="string('')"/>
    <xsl:param name="fieldsize" select="0"/>

    <xsl:variable name="padded" 
                  select="concat($fieldvalue, '                   ')" />
    <xsl:variable name="result" 
                  select="substring($padded,1,$fieldsize)" />

    <xsl:value-of select="$result"/>
  </xsl:template>

</xsl:stylesheet>
XPathDocumemt x = new XPathDocument("yourdoc.xml");    
XPathNavigator n = x.CreateNavigator();    
XPathNodeIterator i = n.Select("root/product");

List<string> fields = new List<string>() { "PID_OWNER_SellerID", "EANCode", "DeliveryDays" }

using (TextWriter w = File.CreateText("c:\\yourfile.csv"))
{
    w.WriteLine("sku, field, value");

    while (i.MoveNext())
    {
        foreach (string field in fields)
        {
            w.WriteLine(string.Format("{0}, {1}, {2}", i.Current.SelectSingleNode("sku").value, field, i.Current.selectSingleNode(field).Value));
        }
    }
}

此樣式表將以指定的格式產生輸出:

<?xml version="1.0" encoding="UTF-8"?>
  <xsl:stylesheet version="1.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" encoding="UTF-8" omit-xml-declaration="yes"/>

  <!--Spacing between column1 and column2 is 11 characters-->
  <xsl:variable name="col1-spaces" select="'           '" />
  <!--Spacing between column2 and column3 is 22 characters-->
  <xsl:variable name="col2-spaces" select="concat($col1-spaces, $col1-spaces)" />

  <xsl:template match="/">
    <!--Generate the heading row first, then apply templates-->
    <xsl:text>sku</xsl:text>
    <!--Add enough spaces after to align the next column-->
    <xsl:value-of select="substring($col1-spaces, 3)"/>
    <xsl:text>field</xsl:text>
    <!--Add enough spaces after to align the next column-->
    <xsl:value-of select="substring($col2-spaces, 5)"/>
    <xsl:text>value&#10;</xsl:text>
    <xsl:apply-templates />
  </xsl:template>

  <!--Do nothing with sku elements-->
  <xsl:template match="sku" />

  <!--For all elements that are children of product, except for sku, do this-->
  <xsl:template match="product/*[not(self::sku)]">
        <xsl:value-of select="preceding-sibling::sku"/>
        <!--Calculate how many spaces are needed using the length of the value of sku -->
        <xsl:value-of select="substring($col1-separator, string-length(preceding-sibling::sku))"/>
        <xsl:value-of select="local-name()" />
        <!--Calculate how many spaces are needed using the length of the name of the current element-->
        <xsl:value-of select="substring($col2-separator, string-length(local-name()))"/>
        <xsl:value-of select="." />
        <xsl:text>&#10;</xsl:text>
  </xsl:template>

</xsl:stylesheet>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM