C# XML 节点缺少元素 - 尝试另存为 CSV
C# XML nodes missing elements - Trying to save as CSV
我找到了很多关于将 XML 保存为 CSV 的帖子,但我的问题是我的 XML 中的某些节点的元素少于其他节点。这导致我的 CSV 列关闭,这不是很有帮助。我正在使用的 XML 数据来自第三方 API。
这是我的代码:
internal static void XmlToCsvFile(XmlDocument doc, string fileName)
{
var xml = new XDocument();
xml = XDocument.Parse(doc.InnerXml);
StringBuilder sb = new StringBuilder(100000);
var xmlDocForHeaders = new XmlDocument();
xmlDocForHeaders.InnerXml = xml.Root.FirstNode.ToString();
var xdocForHeaders = XDocument.Parse(xmlDocForHeaders.InnerXml);
foreach (var element in xdocForHeaders.Elements().Elements())
{
sb.Append($"{element.Name},");
}
sb.Append("\n");
foreach (XElement node in xml.Descendants("Table"))
{
foreach (XElement innerNode in node.Elements())
{
foreach (XElement elements in innerNode.Elements())
{
sb.Append($"\"{elements.Value}\",");
}
sb.Append("\n");
}
sb.Remove(sb.Length - 1, 1);
sb.AppendLine();
}
var csvOut = sb.ToString();
SaveDataToCsvFile(csvOut);
}
我知道我不需要将我的 XmlDocument 转换为 XDocument,但当时这似乎更容易。
如有任何帮助,我们将不胜感激!
谢谢!
编辑:
这是 XML 数据的示例:
<Table>
<Record>
<StoreID>43</StoreID>
<StoreName>30455 Juniper</StoreName>
<Disabled>0</Disabled>
<Abbreviation>UC30455</Abbreviation>
<ManagerEmployeeID>297</ManagerEmployeeID>
<ManagerCommissionable>false</ManagerCommissionable>
<Address>400 Green St.</Address>
<City>Juniper</City>
<StateProv>WA</StateProv>
<ZipPostal>47895</ZipPostal>
<Country>United States</Country>
<PhoneNumber>8056954823</PhoneNumber>
<FaxNumber>5085236524</FaxNumber>
<DistrictNameJuniper South</DistrictName>
<RegionName>High Hills Region</RegionName>
<ChannelName>West Market</ChannelName>
<StoreType>1/2 Tier-PP</StoreType>
<GLCode>5862</GLCode>
<SquareFootage>1100</SquareFootage>
<LocationCode>MX029</LocationCode>
<Latitude>49.5236458952</Latitude>
<Longitude>-192.532150000</Longitude>
<AddressVerified>Not Verified</AddressVerified>
<TimeZone>(GMT-08:00) West Time (US & Canada)</TimeZone>
<AdjustDST>true</AdjustDST>
<CashPolicy>Single-Drawer</CashPolicy>
<MaxCashDrawer>0.0000</MaxCashDrawer>
<Serial_on_OE>false</Serial_on_OE>
<Phone_on_OE>true</Phone_on_OE>
<PAW_on_OE>true</PAW_on_OE>
<Comment_on_OE>false</Comment_on_OE>
<HideCustomerAddress>false</HideCustomerAddress>
<EmailAddress>donotreply@email.com</EmailAddress>
<GeneralLocationNotes>Mon-Sat 9am-8pm, Sun 12pm-5pm</GeneralLocationNotes>
<SaleInvoiceComment />
<BankDetails />
<Taxes>UT - Sales Tax 6.6%, 1.9% E911 Fee (WA)</Taxes>
<Rent>0.0000</Rent>
<PropertyTaxes>0.0000</PropertyTaxes>
<InsuranceAmount>0.0000</InsuranceAmount>
<OtherCharges>0.0000</OtherCharges>
<DepositTaken>0.0000</DepositTaken>
<LeaseNotes />
<InsuranceCompany />
<LandlordNotes />
<LandlordName>COMPANY-JUNIPER/60144582</LandlordName>
<UseLocationEmail>true</UseLocationEmail>
<LocationEntityID>25367</LocationEntityID>
</Record>
<Record>
<StoreID>107</StoreID>
<StoreName>9589 CLC Go Company.com</StoreName>
<Disabled>0</Disabled>
<Abbreviation>CL9589</Abbreviation>
<ManagerEmployeeID>853</ManagerEmployeeID>
<ManagerCommissionable>false</ManagerCommissionable>
<Address>9852 Bland Banks Blvd.</Address>
<City>Honneyton</City>
<StateProv>MI</StateProv>
<ZipPostal>69421</ZipPostal>
<Country>USA</Country>
<PhoneNumber>9595525214</PhoneNumber>
<FaxNumber>3625485236</FaxNumber>
<DistrictName>Recovery Services</DistrictName>
<RegionName>zRetail Support</RegionName>
<ChannelName>zRetail Support</ChannelName>
<StoreType>Care Center</StoreType>
<GLCode>0356</GLCode>
<SquareFootage>2163</SquareFootage>
<AddressVerified>Not Verified</AddressVerified>
<TimeZone>(GMT-07:00) Central Time (US & Canada)</TimeZone>
<AdjustDST>true</AdjustDST>
<CashPolicy>Single-Drawer</CashPolicy>
<MaxCashDrawer>0.0000</MaxCashDrawer>
<Serial_on_OE>false</Serial_on_OE>
<Phone_on_OE>true</Phone_on_OE>
<PAW_on_OE>false</PAW_on_OE>
<Comment_on_OE>false</Comment_on_OE>
<HideCustomerAddress>false</HideCustomerAddress>
<EmailAddress>donotreply@email.com</EmailAddress>
<GeneralLocationNotes />
<SaleInvoiceComment />
<BankDetails />
<Taxes>MI - Honneyton</Taxes>
<Rent>0.0000</Rent>
<PropertyTaxes>0.0000</PropertyTaxes>
<InsuranceAmount>0.0000</InsuranceAmount>
<OtherCharges>0.0000</OtherCharges>
<DepositTaken>0.0000</DepositTaken>
<LeaseNotes />
<InsuranceCompany />
<LandlordNotes />
<LandlordName />
<UseLocationEmail>true</UseLocationEmail>
<LocationEntityID>25397</LocationEntityID>
</Record>
</Table>
如您所见,第一条记录包含纬度和经度元素,但第二条记录没有。这会在转换为 CSV 时抛出所有内容。
再次感谢!
编辑:
根据您的所有精彩评论,以下是最终对我有用的东西!
internal static string XmlToCsvFile(XmlDocument doc, string fileName)
{
var xml = XDocument.Parse(doc.InnerXml);
var sb = new StringBuilder();
var record = new Dictionary<string, string>();
foreach (var element in xml.Descendants("Record").Elements())
{
if (!record.ContainsKey(element.Name.ToString()))
{
record.Add(element.Name.ToString(), "");
}
}
foreach (var key in record.Keys)
{
sb.Append($"{key},");
}
sb.Remove(sb.Length - 1, 1);
sb.AppendLine();
foreach (var node in xml.Descendants("Record"))
{
foreach (var key in record.Keys.ToList())
{
record[key] = "";
}
foreach (var elements in node.Elements())
{
record[elements.Name.ToString()] = elements.Value.ToString();
}
foreach (var value in record.Values)
{
sb.Append($"\"{value}\",");
}
sb.Remove(sb.Length - 1, 1);
sb.AppendLine();
}
var csvOut = sb.ToString();
SaveDataToCsvFile(csvOut);
return csvOut;
}
这是我在评论中所说内容的简要说明。由于您似乎是一次完成此操作,因此您可以将 XML 解析为匿名类型的集合,然后遍历该集合以写出 CSV。
简单示例:
var records = xml.Descedants("Record").Select(r => new
{
StoreID = (string)r.Element("StoreID"),
StoreName = (string)r.Element("StoreName"),
// other elements
};
注意向字符串的显式转换 - 如果缺少元素,这将 return 为 null,这将妥善解决某些记录中缺少某些元素的问题。否则你将不得不编写一堆额外的代码来检查丢失的元素,这会变得非常难看。
一旦你有了匿名类型的集合,你就可以遍历它们来写出 CSV:
foreach(var record in records)
{
// Here you can access the individual properties in the currently selected record
}
我找到了很多关于将 XML 保存为 CSV 的帖子,但我的问题是我的 XML 中的某些节点的元素少于其他节点。这导致我的 CSV 列关闭,这不是很有帮助。我正在使用的 XML 数据来自第三方 API。
这是我的代码:
internal static void XmlToCsvFile(XmlDocument doc, string fileName)
{
var xml = new XDocument();
xml = XDocument.Parse(doc.InnerXml);
StringBuilder sb = new StringBuilder(100000);
var xmlDocForHeaders = new XmlDocument();
xmlDocForHeaders.InnerXml = xml.Root.FirstNode.ToString();
var xdocForHeaders = XDocument.Parse(xmlDocForHeaders.InnerXml);
foreach (var element in xdocForHeaders.Elements().Elements())
{
sb.Append($"{element.Name},");
}
sb.Append("\n");
foreach (XElement node in xml.Descendants("Table"))
{
foreach (XElement innerNode in node.Elements())
{
foreach (XElement elements in innerNode.Elements())
{
sb.Append($"\"{elements.Value}\",");
}
sb.Append("\n");
}
sb.Remove(sb.Length - 1, 1);
sb.AppendLine();
}
var csvOut = sb.ToString();
SaveDataToCsvFile(csvOut);
}
我知道我不需要将我的 XmlDocument 转换为 XDocument,但当时这似乎更容易。
如有任何帮助,我们将不胜感激!
谢谢!
编辑:
这是 XML 数据的示例:
<Table>
<Record>
<StoreID>43</StoreID>
<StoreName>30455 Juniper</StoreName>
<Disabled>0</Disabled>
<Abbreviation>UC30455</Abbreviation>
<ManagerEmployeeID>297</ManagerEmployeeID>
<ManagerCommissionable>false</ManagerCommissionable>
<Address>400 Green St.</Address>
<City>Juniper</City>
<StateProv>WA</StateProv>
<ZipPostal>47895</ZipPostal>
<Country>United States</Country>
<PhoneNumber>8056954823</PhoneNumber>
<FaxNumber>5085236524</FaxNumber>
<DistrictNameJuniper South</DistrictName>
<RegionName>High Hills Region</RegionName>
<ChannelName>West Market</ChannelName>
<StoreType>1/2 Tier-PP</StoreType>
<GLCode>5862</GLCode>
<SquareFootage>1100</SquareFootage>
<LocationCode>MX029</LocationCode>
<Latitude>49.5236458952</Latitude>
<Longitude>-192.532150000</Longitude>
<AddressVerified>Not Verified</AddressVerified>
<TimeZone>(GMT-08:00) West Time (US & Canada)</TimeZone>
<AdjustDST>true</AdjustDST>
<CashPolicy>Single-Drawer</CashPolicy>
<MaxCashDrawer>0.0000</MaxCashDrawer>
<Serial_on_OE>false</Serial_on_OE>
<Phone_on_OE>true</Phone_on_OE>
<PAW_on_OE>true</PAW_on_OE>
<Comment_on_OE>false</Comment_on_OE>
<HideCustomerAddress>false</HideCustomerAddress>
<EmailAddress>donotreply@email.com</EmailAddress>
<GeneralLocationNotes>Mon-Sat 9am-8pm, Sun 12pm-5pm</GeneralLocationNotes>
<SaleInvoiceComment />
<BankDetails />
<Taxes>UT - Sales Tax 6.6%, 1.9% E911 Fee (WA)</Taxes>
<Rent>0.0000</Rent>
<PropertyTaxes>0.0000</PropertyTaxes>
<InsuranceAmount>0.0000</InsuranceAmount>
<OtherCharges>0.0000</OtherCharges>
<DepositTaken>0.0000</DepositTaken>
<LeaseNotes />
<InsuranceCompany />
<LandlordNotes />
<LandlordName>COMPANY-JUNIPER/60144582</LandlordName>
<UseLocationEmail>true</UseLocationEmail>
<LocationEntityID>25367</LocationEntityID>
</Record>
<Record>
<StoreID>107</StoreID>
<StoreName>9589 CLC Go Company.com</StoreName>
<Disabled>0</Disabled>
<Abbreviation>CL9589</Abbreviation>
<ManagerEmployeeID>853</ManagerEmployeeID>
<ManagerCommissionable>false</ManagerCommissionable>
<Address>9852 Bland Banks Blvd.</Address>
<City>Honneyton</City>
<StateProv>MI</StateProv>
<ZipPostal>69421</ZipPostal>
<Country>USA</Country>
<PhoneNumber>9595525214</PhoneNumber>
<FaxNumber>3625485236</FaxNumber>
<DistrictName>Recovery Services</DistrictName>
<RegionName>zRetail Support</RegionName>
<ChannelName>zRetail Support</ChannelName>
<StoreType>Care Center</StoreType>
<GLCode>0356</GLCode>
<SquareFootage>2163</SquareFootage>
<AddressVerified>Not Verified</AddressVerified>
<TimeZone>(GMT-07:00) Central Time (US & Canada)</TimeZone>
<AdjustDST>true</AdjustDST>
<CashPolicy>Single-Drawer</CashPolicy>
<MaxCashDrawer>0.0000</MaxCashDrawer>
<Serial_on_OE>false</Serial_on_OE>
<Phone_on_OE>true</Phone_on_OE>
<PAW_on_OE>false</PAW_on_OE>
<Comment_on_OE>false</Comment_on_OE>
<HideCustomerAddress>false</HideCustomerAddress>
<EmailAddress>donotreply@email.com</EmailAddress>
<GeneralLocationNotes />
<SaleInvoiceComment />
<BankDetails />
<Taxes>MI - Honneyton</Taxes>
<Rent>0.0000</Rent>
<PropertyTaxes>0.0000</PropertyTaxes>
<InsuranceAmount>0.0000</InsuranceAmount>
<OtherCharges>0.0000</OtherCharges>
<DepositTaken>0.0000</DepositTaken>
<LeaseNotes />
<InsuranceCompany />
<LandlordNotes />
<LandlordName />
<UseLocationEmail>true</UseLocationEmail>
<LocationEntityID>25397</LocationEntityID>
</Record>
</Table>
如您所见,第一条记录包含纬度和经度元素,但第二条记录没有。这会在转换为 CSV 时抛出所有内容。
再次感谢!
编辑:
根据您的所有精彩评论,以下是最终对我有用的东西!
internal static string XmlToCsvFile(XmlDocument doc, string fileName)
{
var xml = XDocument.Parse(doc.InnerXml);
var sb = new StringBuilder();
var record = new Dictionary<string, string>();
foreach (var element in xml.Descendants("Record").Elements())
{
if (!record.ContainsKey(element.Name.ToString()))
{
record.Add(element.Name.ToString(), "");
}
}
foreach (var key in record.Keys)
{
sb.Append($"{key},");
}
sb.Remove(sb.Length - 1, 1);
sb.AppendLine();
foreach (var node in xml.Descendants("Record"))
{
foreach (var key in record.Keys.ToList())
{
record[key] = "";
}
foreach (var elements in node.Elements())
{
record[elements.Name.ToString()] = elements.Value.ToString();
}
foreach (var value in record.Values)
{
sb.Append($"\"{value}\",");
}
sb.Remove(sb.Length - 1, 1);
sb.AppendLine();
}
var csvOut = sb.ToString();
SaveDataToCsvFile(csvOut);
return csvOut;
}
这是我在评论中所说内容的简要说明。由于您似乎是一次完成此操作,因此您可以将 XML 解析为匿名类型的集合,然后遍历该集合以写出 CSV。
简单示例:
var records = xml.Descedants("Record").Select(r => new
{
StoreID = (string)r.Element("StoreID"),
StoreName = (string)r.Element("StoreName"),
// other elements
};
注意向字符串的显式转换 - 如果缺少元素,这将 return 为 null,这将妥善解决某些记录中缺少某些元素的问题。否则你将不得不编写一堆额外的代码来检查丢失的元素,这会变得非常难看。
一旦你有了匿名类型的集合,你就可以遍历它们来写出 CSV:
foreach(var record in records)
{
// Here you can access the individual properties in the currently selected record
}