2017-01-12 6 views
0

XML을 CSV로 저장하는 방법에 대한 여러 게시물을 발견했지만 내 문제는 XML의 일부 노드에 다른 요소보다 적은 요소가 있다는 것입니다. 이로 인해 내 CSV 열이 꺼져있어서별로 도움이되지 않습니다. XML 데이터는 제 3 자 API에서 가져옵니다.C# XML 노드 누락 요소 - CSV로 저장하려고 시도했습니다.

여기 내 코드입니다 : 내가하여 XDocument 내을 XmlDocument로 변환 할 필요가 없습니다 알고

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

하지만,이 시간에 쉽게 보였다.

도움이 될 것입니다.

감사합니다!

편집 : 여기

는 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 &amp; 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>[email protected]</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 &amp; 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>[email protected]</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; 
} 
+2

당신은 샘플 XML을 제공 할 수 있습니까? –

+0

데이터를 보유 할 클래스를 만든 다음 LINQ to XML을 통해 XML을 구문 분석하여 누락 된 요소를 적절히 처리하고 CSV로 클래스 컬렉션을 작성합니다. – Tim

+0

또는 심지어 익명 유형으로 변환 한 다음 CSV 파일로 처리 할 수 ​​있습니다. – Tim

답변

0

여기 내 의견에서 말한 내용을 간략히 설명합니다. 한 번에이 작업을 수행하는 것처럼 보이기 때문에 XML을 익명 형식의 컬렉션으로 구문 분석 한 다음 해당 컬렉션을 반복하여 CSV를 작성할 수 있습니다.

간단한 예 :

var records = xml.Descedants("Record").Select(r => new 
       { 
        StoreID = (string)r.Element("StoreID"), 
        StoreName = (string)r.Element("StoreName"), 
        // other elements 
       }; 

참고 문자열로 명시 적 변환 - 요소가 누락 된 경우이 null를 돌려줍니다, 우아 일부 기록에없는 몇 가지 요소와 문제를 해결합니다. 그렇지 않으면 누락 된 요소를 확인하기 위해 많은 코드를 작성해야합니다.이 코드는 매우 추악합니다. 익명 형식의 컬렉션이되면

, 당신은 다음 CSV를 작성하는 그들을 통해 반복 할 수

foreach(var record in records) 
{ 
    // Here you can access the individual properties in the currently selected record 
} 
+0

감사합니다. 귀하의 답변은 올바른 길로 가고 있습니다. 그러나 들어오는 데이터에 따라 동적으로 키 (CSV 헤더가 동적 임)가 필요했기 때문에 사전을 사용하여 데이터를 모두 반복하여 표시하는 방법을 정의했습니다. 내 노드 키 중 하나를 선택하고 새 키를 추가하십시오. 그런 다음 각 노드의 사전에 데이터를 추가 할 수 있습니다. 이것은 잘 작동하는 것처럼 보였지만, 필자는 필 요한 것보다 약간 지저분 할 수 있다고 생각합니다. 청소에 대한 제안은 크게 감사하겠습니다! 위의 편집을보십시오. 모든 도움에 다시 한번 감사드립니다 !! – David