Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
swdev:dotnet:using_xml [2010/10/18 09:28]
smayr
swdev:dotnet:using_xml [2011/11/02 16:13] (current)
smayr
Line 1: Line 1:
-== Using XML ==+= Using XML =
  
 Editing XML Editing XML
  
-Normally, binding a ListView to a datasource (the xml) and let WPF databinding handle the update of the XML data automatically. To do this you could create a [[http://msdn.microsoft.com/en-us/library/84sxtbxh(VS.80).aspx|DataSet from your XML]] and then bind that using ListView.ItemsSource. You would then create a DataTemplate to define the visual representation of a record in your xml. This could be input controls that'd allow you do directly edit the record within your listview. If you prefer a master-detail style view you would bing the detail view to the current item of your listview (e.g. UserControl.DataContext={Binding CurrentItem, ElementName=myListView}). The rest will be handled by WPF. UPDATE: Here is an [[http://msdn.microsoft.com/en-us/library/cc165615.aspx|example]] how you could even bind direcly to your XDocument, so so you do not necessarily have to use DataSets. (Source: [[http://stackoverflow.com/questions/1659734/wpf-and-c-gridview-row-selection-and-xml-datasource-how-to-make-the-connecti|bitbonk on StackOverflow.com]])+Normally, binding a ListView to a datasource (the xml) and let WPF databinding handle the update of the XML data automatically. To do this you could create a [[http://msdn.microsoft.com/en-us/library/84sxtbxh(VS.80).aspx|DataSet from your XML]] and then bind that using ListView.ItemsSource. You would then create a DataTemplate to define the visual representation of a record in your xml. This could be input controls that'd allow you do directly edit the record within your listview. If you prefer a master-detail style view you would bing the detail view to the current item of your listview (e.g. UserControl.DataContext={Binding CurrentItem, ElementName=myListView}). The rest will be handled by WPF. UPDATE: Here is an [[http://msdn.microsoft.com/en-us/library/cc165615.aspx|example]] how you could even bind directly to your XDocument, so so you do not necessarily have to use DataSets. (Source: [[http://stackoverflow.com/questions/1659734/wpf-and-c-gridview-row-selection-and-xml-datasource-how-to-make-the-connecti|bitbonk on StackOverflow.com]])
    
-=== Parsing XML ===+== Parsing XML ==
  
 Example (Source: [[http://stackoverflow.com/questions/55828/best-practices-to-parse-xml-files|Lukas Šalkauskas]]): Example (Source: [[http://stackoverflow.com/questions/55828/best-practices-to-parse-xml-files|Lukas Šalkauskas]]):
Line 38: Line 38:
   * [[http://msdn.microsoft.com/en-us/library/bb387098.aspx|LINQ to XML]]   * [[http://msdn.microsoft.com/en-us/library/bb387098.aspx|LINQ to XML]]
   * [[http://msdn.microsoft.com/en-us/library/182eeyhh.aspx|Intro to XML Serialization]]   * [[http://msdn.microsoft.com/en-us/library/182eeyhh.aspx|Intro to XML Serialization]]
-=== Using LINQ with XML ===+ 
 +== Using LINQ with XML == 
 + 
 +Example: (Source: [[http://stackoverflow.com/questions/1659734/wpf-and-c-gridview-row-selection-and-xml-datasource-how-to-make-the-connecti|StackOverflow.com]]) 
 +<code csharp> 
 +XDocument xml = XDocument.Load(@"D:\devel\VS\pchart\charts.xml"); 
 + 
 +var query = from p in xml.Elements("charts").Elements("chart"
 +select p; 
 +foreach (var record in query) 
 +
 +  chartListView.Items.Add(new {  
 +      Name = record.Attribute("Name").Value,  
 +      Type = record.Attribute("Type").Value,  
 +      defaultFontName = record.Attribute("defaultFontName").Value,  
 +      defaultFontSize = record.Attribute("defaultFontSize").Value,  
 +      ID record.Attribute("ID").Value  
 +    } 
 +  ); 
 +
 +</code> 
 Converting between List<T> and IEnumerable<T>: ([[http://stackoverflow.com/questions/472669/c-freely-convert-between-listt-and-ienumerablet|Source: DrJokepu]]) Converting between List<T> and IEnumerable<T>: ([[http://stackoverflow.com/questions/472669/c-freely-convert-between-listt-and-ienumerablet|Source: DrJokepu]])
 <code csharp> <code csharp>
Line 46: Line 67:
 </code> </code>
  
-Beware however that myEnumarable is the same object instance as myList, but listAgain is not the same object instance as myEnumerable. Depending on what you want to do and what myEnumerable is, "List<string> listAgain = myEnumerable as List<string>;" might be better. – ChrisW Jan 23 '09 at 12:12+Beware however that myEnumarable is the same object instance as myList, but listAgain is not the same object instance as myEnumerable. Depending on what you want to do and what myEnumerable is, ''"List<string> listAgain = myEnumerable as List<string>;"'' might be better. – ChrisW
  
-Chrisw: Oh yes, you're right of course, but the IEnumerable<T> interface is immutable so it will not cause problems in that direction and casting back just feels dirty when you have a function that will take care of type safety. – DrJokepu Jan 23 '09 at 12:17+Chrisw: Oh yes, you're right of course, but the ''IEnumerable<T>'' interface is immutable so it will not cause problems in that direction and casting back just feels dirty when you have a function that will take care of type safety. – DrJokepu
  
-You also could just use the original myList object. (I guess I don't really get the question) – sth Jan 23 '09 at 12:27+You also could just use the original myList object. (I guess I don't really get the question) – sth
        
 It's just that if he edits myList then he would be editing myEnumrable, but if he edits listAgain then he wouldn't be editing myEnumerable. It's just that if he edits myList then he would be editing myEnumrable, but if he edits listAgain then he wouldn't be editing myEnumerable.
  
-A List<T> is an IEnumerable<T>, so actually, there's no need to 'convert' a List<T> to an IEnumerable<T>. Since a List<T> is an IEnumerable<T>, you can simply assign a List<T> to a variable of type IEnumerable<T>.+''List<T>'' is an ''IEnumerable<T>'', so actually, there's no need to 'convert'''List<T>'' to an ''IEnumerable<T>''. Since a ''List<T>'' is an ''IEnumerable<T>'', you can simply assign a ''List<T>'' to a variable of type ''IEnumerable<T>''.
  
-The other way around, not every IEnumerable<T> is a List<T> offcourse, so then you'll have to call the ToList() member method of the IEnumerable<T>. +The other way around, not every ''IEnumerable<T>'' is a ''List<T>'' of course, so then you'll have to call the ''ToList()'' member method of the ''IEnumerable<T>''.
 Source: [[http://stackoverflow.com/questions/472669/c-freely-convert-between-listt-and-ienumerablet|David B, Frederik Gheysels]] Source: [[http://stackoverflow.com/questions/472669/c-freely-convert-between-listt-and-ienumerablet|David B, Frederik Gheysels]]
  
-== References ==+Examples = 
 +== Loading and Parsing an XML File into a Data Structure == 
 + 
 +For an XML file like this: 
 +<code xml> 
 +<?xml version="1.0"?> 
 +<Workshops xmlns=""> 
 +  <Workshop> 
 +    <Name>Acme's 12th Annual Continuing Education Workshop</Name> 
 +    <RecID>12</RecID> 
 +    <WorkshopID>AcmeWorkshop12</WorkshopID> 
 +    <VenueInfo> 
 +      <Organization>Orlando Marriott Lake Mary</Organization> 
 +      <AddressLn1>1501 International Parkway</AddressLn1> 
 +      <City>Lake Mary</City> 
 +      <StateProv>FL</StateProv> 
 +      <PostalCode>32746</PostalCode> 
 +      <PhoneHome>407.995.1100</PhoneHome> 
 +      <PhoneWork>800.380.7724</PhoneWork> 
 +      <Fax>407.995.1101</Fax> 
 +      <Website>www.marriotthotels.com</Website> 
 +    </VenueInfo> 
 +    <Days> 
 +      <DateTime>2008-06-11</DateTime> 
 +      <DateTime>2008-06-12</DateTime> 
 +    </Days> 
 +    <PricingDailyPackages> 
 +      <PricingPackage> 
 +        <Name>Premium</Name> 
 +        <Pricing>100</Pricing> 
 +      </PricingPackage> 
 +      <PricingPackage> 
 +        <Name>Standard</Name> 
 +        <Pricing>200</Pricing> 
 +      </PricingPackage> 
 +      <PricingPackage> 
 +        <Name>Other</Name> 
 +        <Pricing>200</Pricing> 
 +      </PricingPackage> 
 +    </PricingDailyPackages> 
 +  </Workshop> 
 +  <Workshop> 
 +    <Name>Acme's 13th Annual Continuing Education Workshop</Name> 
 +    <RecID>13</RecID> 
 +    <WorkshopID>AcmeWorkshop13</WorkshopID> 
 +    <VenueInfo> 
 +      <Organization>Orlando Marriott Lake Mary</Organization> 
 +      <AddressLn1>1501 International Parkway</AddressLn1> 
 +      <City>Lake Mary</City> 
 +      <StateProv>FL</StateProv> 
 +      <PostalCode>32746</PostalCode> 
 +      <PhoneHome>407.995.1100</PhoneHome> 
 +      <PhoneWork>800.380.7724</PhoneWork> 
 +      <Fax>407.995.1101</Fax> 
 +      <Website>www.marriotthotels.com</Website> 
 +    </VenueInfo> 
 +    <Days> 
 +      <DateTime>2009-06-15</DateTime> 
 +      <DateTime>2009-06-16</DateTime> 
 +    </Days> 
 +    <PricingDailyPackages> 
 +      <PricingPackage> 
 +        <Name>Premium</Name> 
 +        <Pricing>100</Pricing> 
 +      </PricingPackage> 
 +      <PricingPackage> 
 +        <Name>Standard</Name> 
 +        <Pricing>200</Pricing> 
 +      </PricingPackage> 
 +      <PricingPackage> 
 +        <Name>Other</Name> 
 +        <Pricing>200</Pricing> 
 +      </PricingPackage> 
 +    </PricingDailyPackages> 
 +  </Workshop> 
 +</Workshops> 
 +</code> 
 + 
 +To format XML content to fit in a data structure like this: 
 +<code csharp> 
 +    //======================================================================== 
 +    // Class TWorkshop 
 +    //======================================================================== 
 +    public class TWorkshop 
 +    { 
 +        public int RecID                          { get; set; } 
 +        public string WorkshopID                  { get; set; } 
 +        public string Name                        { get; set; } 
 +        public TContactInfo VenueInfo             { get; set; } 
 +        public List<DateTime> Days                { get; set; } 
 +        public List<TPricingPackage> PricingDailyPackages  { get; set; } 
 +        public string CancellationPolicy          { get; set; } 
 +        public string Instructions                { get; set; } 
 +        public string HotelAccommodations         { get; set; } 
 +  } 
 +</code> 
 + 
 +We can implement the logic in a function like this: 
 +<code csharp> 
 +//----------------------------------------------------------------------------------------- 
 +/// <summary> 
 +/// Load data from an XML file. 
 +/// </summary> 
 +/// <param name="AFilename">Filename of XML file to load</param> 
 +/// <returns>true if success, false if not</returns> 
 +//----------------------------------------------------------------------------------------- 
 +public bool LoadFromXmlFile(string AFilename) 
 +
 + if (System.IO.File.Exists(AFilename)) 
 +
 + xmldoc = XDocument.Load(AFilename); 
 + if (xmldoc != null) 
 +
 + // parse xml data and load into TWorkshopList object 
 + List<XElement> xmldata = new List<XElement>(); 
 + xmldata = xmldoc.Root.Elements("Workshop").ToList<XElement>(); 
 + 
 + foreach (XElement el in xmldata) 
 +
 + // create TWorkshop record 
 + TWorkshop currec = new TWorkshop(); 
 + 
 + // Parse xml record, and add it 
 + currec.VenueInfo.Clear(); 
 + currec.Name                         = el.Element("Name").Value; 
 + currec.WorkshopID                   = el.Element("WorkshopID").Value; 
 + currec.RecID                        = Convert.ToInt32(el.Element("RecID").Value); 
 + currec.VenueInfo.Organization       = el.Element("VenueInfo").Element("Organization").Value; 
 + currec.VenueInfo.Address.AddressLn1 = el.Element("VenueInfo").Element("AddressLn1").Value; 
 + currec.VenueInfo.Address.City       = el.Element("VenueInfo").Element("City").Value; 
 + currec.VenueInfo.Address.StateProv  = el.Element("VenueInfo").Element("StateProv").Value; 
 + currec.VenueInfo.Address.PostalCode = el.Element("VenueInfo").Element("PostalCode").Value; 
 + currec.VenueInfo.PhoneHome          = el.Element("VenueInfo").Element("PhoneHome").Value; 
 + currec.VenueInfo.PhoneWork          = el.Element("VenueInfo").Element("PhoneWork").Value; 
 + currec.VenueInfo.Fax                = el.Element("VenueInfo").Element("Fax").Value; 
 + currec.VenueInfo.Website            = el.Element("VenueInfo").Element("Website").Value; 
 + currec.CancellationPolicy           = el.Element("CancellationPolicy").Value; 
 + currec.Instructions                 = el.Element("Instructions").Value; 
 + currec.HotelAccommodations          = el.Element("HotelAccommodations").Value; 
 + 
 + // Days: extra processing 
 + currec.Days.Clear(); 
 + List<XElement> elDays = el.Element("Days").Elements("DateTime").ToList<XElement>(); 
 + foreach (XElement elDay in elDays) 
 +
 + string DateInInvariantCultureStrFmt = elDay.Value; 
 + DateTime DateLocalized = new DateTime(); 
 + try 
 +
 + DateLocalized = DateTime.Parse(DateInInvariantCultureStrFmt,  
 + System.Globalization.CultureInfo.InvariantCulture,  
 + System.Globalization.DateTimeStyles.None); 
 +
 + catch(FormatException exc) 
 +
 + throw new FormatException(string.Format("'{0}' is not in an acceptable format. [{1}]", DateInInvariantCultureStrFmt, exc.Message)); 
 +
 + currec.Days.Add(DateLocalized); 
 +
 + 
 + // PricingDailyPackages: extra processing 
 + currec.PricingDailyPackages.Clear(); 
 + List<XElement> elPkgs = el.Element("PricingDailyPackages").Elements("PricingPackage").ToList<XElement>(); 
 + foreach (XElement elPkg in elPkgs) 
 +
 + TPricingPackage pkg = new TPricingPackage(); 
 + pkg.Name    = elPkg.Element("Name").Value; 
 + pkg.Pricing = Convert.ToInt32(elPkg.Element("Pricing").Value); 
 + currec.PricingDailyPackages.Add(pkg); 
 +
 +  
 + // add TWorkshop record 
 + this.Add(currec); 
 +
 + 
 + // Success 
 + return true; 
 +
 + else  
 +
 + // Failed to load data from file 
 + return false; 
 +
 + 
 +
 + else 
 +
 + // Failed. File not found. 
 + return false; 
 +
 +}   
 +</code> 
 + 
 +== Example using XmlDocument, XmlElement, XmlNodeList == 
 + 
 +Sample Data: 
 +<code xml> 
 +<FittingSession> 
 +  <Instruments> 
 +    <Instrument Name="Cue" ProductCode="PROD_CUE" EarSide="0" MaxMemories="5"> 
 +      <AutofitEnvironments> 
 +        <AutofitEnvironment Name="Undefined" Index="0" Memory="0" /> 
 +        <AutofitEnvironment Name="Undefined" Index="0" Memory="1" /> 
 +        <AutofitEnvironment Name="Undefined" Index="0" Memory="2" /> 
 +        <AutofitEnvironment Name="Undefined" Index="0" Memory="3" /> 
 +      </AutofitEnvironments> 
 +      <ParametersConfig> 
 +        <Param Name="number_of_programs" Value="0" /> 
 +        <Param Name="program_switch_mode" Value="0" /> 
 +        . . . 
 +      </ParametersConfig> 
 +      <ParametersCustom> 
 +        . . . 
 +      </ParametersCustom> 
 +      <ParametersMemory> 
 +        <Memory Number="0"> 
 +          <Param Name="Input_mux" Value="0" /> 
 +          <Param Name="Preamp_gain0" Value="4" /> 
 +          . . . 
 +        </Memory> 
 +        <Memory Number="1"> 
 +          . . . 
 +        </Memory> 
 +        <Memory Number="2"> 
 +          . . . 
 +        </Memory> 
 +        <Memory Number="3"> 
 +          . . . 
 +        </Memory> 
 +      </ParametersMemory> 
 +    </Instrument> 
 +     
 +    <Instrument Name="Cue" ProductCode="PROD_CUE" EarSide="1" MaxMemories="5"> 
 +      . . . 
 +    </Instrument> 
 +     
 +  </Instruments> 
 +</FittingSession> 
 +</code> 
 + 
 +Code to load Xml document: 
 +<code csharp> 
 +///---------------------------------------------------------------------------------------- 
 +/// <summary> 
 +/// Load data from XML file. 
 +/// </summary> 
 +/// <param name="FileName"></param> 
 +///---------------------------------------------------------------------------------------- 
 +public void LoadFromXml(string FileName) 
 +
 +    // using System.Xml; 
 +    XmlDocument xmlDoc = new XmlDocument();  // create an xml document object. 
 +    xmlDoc.Load(FileName);                   // load the XML document from the specified file. 
 + 
 +    try 
 +    { 
 +        for (int side = 0; side < 2; side++) 
 +        { 
 +            // Get elements. 
 +            //XmlNodeList ParamConfigLst = xmlDoc["FittingSession"]["Instruments"]["Instrument"]["ParametersConfig"].GetElementsByTagName("Param"); 
 +            //XmlNodeList ParamMemoryLst = xmlDoc["FittingSession"]["Instruments"]["Instrument"]["ParametersMemory"].GetElementsByTagName("Param"); 
 +            //XmlNodeList ParamCustomLst = xmlDoc["FittingSession"]["Instruments"]["Instrument"]["ParametersCustom"].GetElementsByTagName("Param"); 
 +            XmlNodeList HI = xmlDoc["FittingSession"]["Instruments"].GetElementsByTagName("Instrument"); 
 +            XmlNodeList AutofitEnv = HI[side].ChildNodes[0].ChildNodes; 
 +            XmlNodeList ParamConfigLst = HI[side].ChildNodes[1].ChildNodes; 
 +            XmlNodeList ParamCustomLst = HI[side].ChildNodes[2].ChildNodes; 
 +            XmlNodeList ParamMemoryLst = HI[side].ChildNodes[3].ChildNodes; 
 + 
 +            // load data into package 
 +            LoadXmlNodeListToIntArray(AutofitEnv, m_InstrumentParams[side].AutofitEnvironments); 
 +            LoadXmlNodeListToDevParamList(ParamConfigLst, m_InstrumentParams[side].ParametersConfig); 
 +            LoadXmlNodeListToDevParamList(ParamCustomLst, m_InstrumentParams[side].ParametersCustom); 
 +            LoadXmlNodeListParamMemToDevParamList(ParamMemoryLst, m_InstrumentParams[side].ParametersMemory); 
 +        } 
 +    } 
 +    catch (Exception exc) 
 +    { 
 +        TAppLog.LogException("TFittingSession.LoadFromXml", exc); 
 +    } 
 +
 + 
 +///---------------------------------------------------------------------------------------- 
 +/// <summary> 
 +/// Load Xml node list to Device Parameter list. 
 +/// </summary> 
 +/// <param name="srcParamDataLst"></param> 
 +/// <param name="dstParamDataLst"></param> 
 +///---------------------------------------------------------------------------------------- 
 +private void LoadXmlNodeListToIntArray(XmlNodeList srcParamDataLst, int[] dstIntArray) 
 +
 +    int CurAutofitEnvMemIdx = 0; 
 +    for (int i = 0; i < srcParamDataLst.Count; i++) 
 +    { 
 +        CurAutofitEnvMemIdx              = Convert.ToInt32(srcParamDataLst[i].Attributes["Memory"].InnerText); 
 +        dstIntArray[CurAutofitEnvMemIdx] = Convert.ToInt32(srcParamDataLst[i].Attributes["Index"].InnerText); 
 +    } 
 +
 + 
 +///---------------------------------------------------------------------------------------- 
 +/// <summary> 
 +/// Load Xml node list to Device Parameter list. 
 +/// </summary> 
 +/// <param name="srcParamDataLst"></param> 
 +/// <param name="dstParamDataLst"></param> 
 +///---------------------------------------------------------------------------------------- 
 +private void LoadXmlNodeListToDevParamList(XmlNodeList srcParamDataLst, TDevParamList dstParamDataLst) 
 +
 +    for (int i = 0; i < srcParamDataLst.Count; i++) 
 +    { 
 +        dstParamDataLst.Add(new TDevParam() 
 +        { 
 +            Name = srcParamDataLst[i].Attributes["Name"].InnerText, 
 +            Value = Convert.ToInt32(srcParamDataLst[i].Attributes["Value"].InnerText) 
 +        }); 
 +    } 
 +
 + 
 +///---------------------------------------------------------------------------------------- 
 +/// <summary> 
 +/// Load Xml node list to Device Parameter list. 
 +/// </summary> 
 +/// <param name="srcParamMemLst"></param> 
 +/// <param name="dstParamMemLst"></param> 
 +///---------------------------------------------------------------------------------------- 
 +private void LoadXmlNodeListParamMemToDevParamList(XmlNodeList srcParamMemLst, TDevParamList[] dstParamMemLst) 
 +
 +    // Format: 
 +    //   <ParametersMemory> 
 +    //     <Memory Number='0'><Param...><Param...>...</Memory> 
 +    //     <Memory Number='1'>...</Memory> 
 +    //     <Memory Number='2'>...</Memory> 
 +    //     <Memory Number='3'>...</Memory> 
 +    //   </ParametersMemory> 
 +    XmlNodeList[] MemParams = new XmlNodeList[srcParamMemLst.Count]; 
 +    for (int mem = 0; mem < MemParams.Length; mem++) 
 +    { 
 +        MemParams[mem] = srcParamMemLst.Item(mem).ChildNodes;  
 + 
 +        for (int paramidx = 0; paramidx < MemParams[mem].Count; paramidx++) 
 +        { 
 +            dstParamMemLst[mem].Add(new TDevParam() 
 +            { 
 +                Name = MemParams[mem][paramidx].Attributes["Name"].InnerText, 
 +                Value = Convert.ToInt32(MemParams[mem][paramidx].Attributes["Value"].InnerText) 
 +            }); 
 +        } 
 +    } 
 +
 + 
 +///---------------------------------------------------------------------------------------- 
 +/// <summary> 
 +/// Get the Xml node list of requested tag name for the given Xml document section. 
 +/// </summary> 
 +/// <param name="xmlDoc"></param> 
 +/// <param name="SectionName"></param> 
 +/// <param name="ElementTagName"></param> 
 +/// <returns></returns> 
 +///---------------------------------------------------------------------------------------- 
 +private XmlNodeList GetElements(XmlDocument xmlDoc, string SectionName, string ElementTagName) 
 +
 +    //XmlNode xmlnodeSection = xmlDoc.GetElementsByTagName(SectionName)[0];  // get section tree (eg: Data3) 
 +    XmlNode xmlnodeSection = xmlDoc.GetElementsByTagName(SectionName)[0];  // get section tree (eg: Data3) 
 + 
 +    // Convert Section xmlnode into Section xmldoc 
 +    // 1. Create empty xmldoc 
 +    // 2. Import Section xmlnode into it. 
 +    XmlDocument xmldocSection = new XmlDocument(); 
 +    xmldocSection.LoadXml("<FittingSession></FittingSession>");              // load DocumentType 
 +    XmlNode xn = xmldocSection.ImportNode(xmlnodeSection, true /* deep */);  // import node 
 +    xmldocSection.DocumentElement.AppendChild(xn);                           // associate imported node into correct hierarchy position 
 + 
 +    // Search for requested Elements in this Section 
 +    return xmldocSection.GetElementsByTagName(ElementTagName);               // search for child nodes == Param 
 +
 +</code> 
 + 
 += References =
   * [[http://msdn.microsoft.com/en-us/library/cc165615.aspx|MSDN: How To: Bind to XDocument, XElement, or LINQ for XML Query Results]]   * [[http://msdn.microsoft.com/en-us/library/cc165615.aspx|MSDN: How To: Bind to XDocument, XElement, or LINQ for XML Query Results]]
   * [[http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.aspx|MSDN: XElement Class]]   * [[http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.aspx|MSDN: XElement Class]]