2010-03-25 95 views
1

使用正则表达式转换为乱七八糟的XML后,我现在需要再次更改它。 这个源文件将XML文件转换为CSV

<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 

我把它这是正则表达式”范围之内,并用XSL来完成?

+0

你正在寻找的代码来解决这个问题?或者,现有的工具将xml转换为csv? – geffchang 2010-03-25 15:30:51

+0

看看这个问题:http://stackoverflow.com/questions/365312/xml-to-csv-using-xslt – gooch 2010-03-25 15:31:43

+1

你想要什么样的编程语言?它可以通过XSL完成,也可以使用.NET或其他语言来完成。 – 2010-03-25 15:33:24

回答

4

下面是一些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> 
+0

有更好的方法来形成这个XSLT。但这是最短的。如果添加更多元素,我会有一个更长的示例,它会自动运行。但是该样式表与上面的整个答案一样长。 – 2010-03-25 17:12:13

+0

我对这个例子很感兴趣,因为我实际上在XML中有大约84种不同类型的元素。 – skerit 2010-03-26 15:27:26

+0

我将在本周末发布在我的博客上(我真的不想垃圾邮件这个答案。)但基本的想法是我发现了一个填充模板来处理固定宽度,然后我写了一个递归模板来查询每个产品并使用local-name(。)循环子元素...很难描述使用方便的东西。 – 2010-03-26 16:05:28

6

尝试使用正则表达式解析XML通常是一个糟糕的主意,因为有一种无限的方式来格式化结构相同的XML文档,然而它将会扫描正则表达式。

对于不是很大的文件,一定要使用XSL,记住指定'text'作为输出方法。不要忘记,如果你必须的话,你可以通过编程方式调用XSL进程 - 大多数语言都可以让你这么做。

对于大文件,请考虑编写一个使用流API的小程序(例如SAX或推解析器API之一)。

1
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)); 
     } 
    } 
} 
1

该样式会产生特定的格式输出:

<?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> 
+0

这就是我所需要的,尽管一些字段名称非常大。 当我尝试在“XSL Results”firefox插件中使用它时,它会抱怨样式表中有错误... 你用什么来应用这个? – skerit 2010-03-26 14:56:02

+0

我想过用这种方式来填充...我应该简单地通过我的扩展示例,然后再发布它,谢谢! – 2010-03-26 16:07:49