使用正则表达式转换混乱的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
我认为这是在正则表达式的范围之外,必须用XSL完成?
答案 0 :(得分:6)
尝试使用正则表达式解析XML通常是一个坏主意,因为有一种无限的方式来格式化结构相同的XML文档,但是会破坏你的正则表达式。
对于非大规模的文件,一定要使用XSL,记住指定'text'作为输出方法。不要忘记,如果必须,您可以以编程方式调用XSL进程 - 大多数语言都允许您这样做。
对于大文件,请考虑编写一个使用流API的小程序(例如SAX或其中一个推送解析器API)。
答案 1 :(得分: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
</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>
</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>
答案 2 :(得分: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));
}
}
}
答案 3 :(得分: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 </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> </xsl:text>
</xsl:template>
</xsl:stylesheet>