Retrieve an ancestor attribute - c#

I am attempting to build an external XML config file for several applications, to house their connection strings. The file looks something like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<configuration>
<Connection Name = "Primary">
<Server Name = "DisneyWorld">
<Database Name ="MagicKingdom">
<Project Name ="Rides">
<Login Username="Mickey" Password="Mouse" Encrypted="False"/>
</Project>
<Project Name = "Food">
<Login Username="Goofy" Password="123456" Encrypted="True"/>
</Project>
<Project Name ="Shows">
<Login Username ="Minnie" Password="Mouse" Encrypted="False"/>
</Project>
</Database>
</Server>
<Server Name = "Epcot">
<Database Name ="LandOfTomorrow">
<Project Name = "Innovation">
<Login Username="Daffy" Password="Duck" Encrypted="False"/>
</Project>
</Database>
</Server>
</Connection>
</configuration>
There will be a secondary connection, in case the primary one is down. What I am wanting to do is search for Project: Food get its log in information, Database and server. Which I can do with this bit of code:
XDocument doc = XDocument.Load(path);
var query = from connection in doc.Descendants("Connection")
where connection.Attribute("Name").Value == "Primary"
from project in connection.Descendants("Project")
where project.Attribute("Name").Value == targetProject
select new
{
Server = connection.Element("Server").Attribute("Name").Value,
Database = project.Parent.Attribute("Name").Value,
UserName = project.Element("Login").Attribute("Username").Value,
Password = project.Element("Login").Attribute("Password").Value,
Encrypted = project.Element("Login").Attribute("Password").Value
};
The code works great, with the exception that it is hard-coded to the current structure.
On the lines
Server = connection.Element("Server").Attribute("Name").Value,
and
Database = project.Parent.Attribute("Name").Value,
I would like to be able to get their values, from project.Ancestors("Server"), but I do understand how to achieve this.

Do you mean something like:
Server = project.Ancestors("Server").Single().Attribute("Name").Value;
Database = project.Ancestors("Database").Single().Attribute("Name").Value;
That's assuming there will only ever be a single ancestor for a given element, of course.

Related

Deserialize the xml configuration file present in different location

I am trying to Deserialize XML configuration file stored in %LOCALAPPDATA%\Configuration\Configuration.XML. I want to read the key value section and store it in the local variable.
The XML file looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="FolderPath" value="C:\\Data" />
<add key="Name" value="xxx" />
<add key="Type" value="xxx" />
</appSettings>
</configuration>
ConfigurationManager.Appsettings.Get("FolderPath") does not work because the xml file is in the different location.
So I tried with the following code, which does not work.
var configFile = Path.Combine(Environment.GetEnvironmentVariable("LocalAppData"), "Configuration", "Configuration.XML")
var configuration = ConfigurationManager.OpenExeConfiguration(configFile);
var appSettings = configuration.GetSection("appSettings").SectionInformation;
Please help me to read the configuration.XML as shown above.
Thank you.
Thanks for your suggestions #jdweng.
I was able to solve the issue
var configFile = Path.Combine(Environment.GetEnvironmentVariable("LOCALAPPDATA"), "Configuration", "Configuration.XML"));
if (File.Exists(configFile))
{
ConfigurationDetails = new Dictionary<string, string>();
XDocument doc = XDocument.Load(configFile);
var elements = doc.Descendants("add");
foreach (var element in elements)
{
ConfigurationDetails.Add(element.Attribute("key").Value, element.Attribute("value").Value);
}
}

Simple XML file to store info

I want to create a simple XML file to store some settings that can be easily changed in a text editor. This is my XML file:
<connection>
<hostname>the.host.name</hostname>
<port>1000</port>
<database>theDbName</database>
</connection>
I am trying to use Linq to XML now to read that info into my program, but it gives me an error:
Could not find an implementation of the query pattern for source type 'System.Xml.Linq.XElement'. 'Select' not found.
My code is as follows:
XElement root = XElement.Load(".\\Resources\\Connection.xml");
string host = from el in root.Element("hostname") select el.Element("text");
XDocument xDoc = XDocument.Load(".\\Resources\\Connection.xml");
string host = (string)xDoc.Root.Element("hostname");
I think you're confused on how your XML structure should look and the way you read that XML with LinQ. First of all place your connection-element in a root called connections. Your XML looks like this now:
<?xml version="1.0" encoding="utf-8"?>
<connections>
<connection>
<hostname>the.host.name</hostname>
<port>1000</port>
<database>theDbName</database>
</connection>
</connections>
Now you can select the elements under that root and read all the data from it. Example code looks like following:
var root = XElement.Load(".\\Resources\\Connection.xml");
var connection = root.Elements("connection").FirstOrDefault();
if(connection != null)
{
var host = connection.Element("hostname").Value;
//do something with 'host'
}
Update:
If you don't want a root element 'connections', you can omit it and use following code to read the XML:
var xmlDoc = XDocument.Load("G:\\Connection.xml");
var connection = xmlDoc.Descendants("connection").FirstOrDefault();
if(connection != null)
{
var host = connection.Element("hostname").Value;
//do something with 'host'
}

output XML to dataset

I've been trying to read an xml file from an external source to get it into a dataset. I've taken the schema and compiled my class through xsd and have loaded it into the solution.
my xml:
<?xml version="1.0" encoding="UTF-8" standalone="true"?>
<CAMDealerManifest AssetURL="http://www.the placewherethefilelives.com/CAMPublic/d98c8185/" DealerCode="41065" DealerGuid="bc0d0bc8-b37b-11e3-a345-ac162dbc18f8" DealerName="Ron Hibbard Toyota" ManifestId="13" ManifestURL="http://www.toyota.com/CAMPublic/d/41065-bc0d0bc8.xml" Path="41065-bc0d0bc8" ProviderId="1011" WebsiteVendorName="WorldDealer">
<CAMCampaigns count="15" dateTime="2014-09-16T17:18:40.877-07:00">
<CAMCampaign ManifestId="13" endDate="2014-12-31T11:59:59-08:00" flightDates="08/01/14 - 12/31/14" geography="National" groupName="National" id="68" name="National - Corolla Style Elevated" priority="0" required="false" startDate="2014-08-01T12:00:00-07:00">
<CAMCreative SubGroup="Corolla Style Elevated" Id="49" Name="National - Corolla Style Elevated" ImageAltText="Toyota's national banner for the stylish 2014 Corolla" ImageSearchTerms="Toyota, 2014 Corolla, Style Elevated, New Heights" Link="New Inventory" Model="Corolla" MonthYear="08-2014" Priority="3" Required="false">
<CAMCreativeSource CAMAssetCount="1" Height="409" Width="990" MediaBinAssetId="0E1C886A-C5CE-4409-AD36-7070D614A7A6" MediaBinFileName="03-14_01_2014_nat-style-elevated_990x409_0000000460_corolla_o_xta.jpg">
<CAMAsset Path="National/Corolla-Style-Elevated/National---Corolla-Style-Elevated/990/409/" Id="1273" Name="08-14_01_National-Corolla-Style-Elevated_990x409_431_Corolla_O_xta.jpg" Height="409" Width="990" assetType="JPG" Guid="b9f4d3cd-fefd-4ff3-b209-338f409e551c" Md5Hex="3e328dc32a2db9fc1f3d6a2167d3e5d2">
<CAMTracking>
<SiteCatalyst version="1.0">
<Click tmsomni.events="event28" tmsomni.products=";08-14_01_National-Corolla-Style-Elevated_990x409_431_Corolla_O_xta;;;event28=1"/>
<Impression tmsomni.events="event29" tmsomni.products=";08-14_01_National-Corolla-Style-Elevated_990x409_431_Corolla_O_xta;;event29=1;evar43=img|evar61=corolla|evar54=o|evar49={$CAM_PAGE_POSITION}"/>
</SiteCatalyst>
</CAMTracking>
</CAMAsset>
</CAMCreativeSource>
</CAMCreative>
</CAMCampaign>
</CAMCampaigns>
<CAMExpiredCampaigns count="0" dateTime="2014-09-16T17:18:40.873-07:00"/>
</CAMDealerManifest>
I can't seem to get this xml to list or put into a dataset. I'm new to deserializing xml and could use some assistance.
Simply call ReadXml with the path to the file:
var dataSet = new DataSet();
dataSet.ReadXml(string PathToFile);
Works pretty well; will even create all the relations (notice CAMDealerManifestId in the screenshot).
Your file went in with only a modification to the XML declaration -- had to change standalone value from true to yes:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
If you're reading this in as a string, you could do something like this:
var xmlString = HoweverYouGetTheString().Split(new string[] { "\r\n" }, StringSplitOptions.None);
xmlString[0] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
using (var reader = new System.IO.StringReader(String.Join("\r\n", xmlString)))
{
dataSet.ReadXml(reader);
}

Read/write Database Connection string in xml file using c# Windows Form

I am developing an c# application in which I need to fetch data from oracle database server.
In my application I do not want to make a hard coded connection string because sometimes we have to connect it with different DB (for testing purpose it has same schema).
For this I have a plan that I create an xml file and a new form(with admin rights) using this form I update/insert database credentials in xml file or use app.config, but the problem is i don't have any idea how to read and write xml file in predefined manner (in same manner as a connection string should be).
Can you please help me out for creating new xml file or have any batter idea?
how about this code?
public static string ClientName, DbType, ConnectionString;
static DB()
{
try
{
DataTable Dt = new DataTable("Settings");
DataColumn Client = new DataColumn("Client", typeof(string));
DataColumn DataBaseType = new DataColumn("DataBaseType", typeof(string));
DataColumn ConString = new DataColumn("ConnectionString", typeof(string));
Dt.Columns.Add(Client);
Dt.Columns.Add(DataBaseType);
Dt.Columns.Add(ConString);
Dt.ReadXml(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Settings.xml");
DB.ClientName = Dt.Rows[0]["Client"].ToString();
DB.DbType = Dt.Rows[0]["DataBaseType"].ToString();
DB.Port = Dt.Rows[0]["Port"].ToString();
DB.ConnectionString = Dt.Rows[0]["ConnectionString"].ToString();
}
catch(Exception ex)
{
// Exception message
}
and xml file code is
<?xml version="1.0" standalone="yes"?>
<DocumentElement>
<Settings>
<Client>DSCL</Client>
<DataBaseType>ORACLE</DataBaseType>
<ConnectionString>providerName=system.data.oracleclient;User ID=****;password=****;Data Source=*****;Persist Security Info=True;Provider=OraOLEDB.Oracle;</ConnectionString>
</Settings>
</DocumentElement>
Create that class
[Serializable()]
public class Car
{
[System.Xml.Serialization.XmlElement("StockNumber")]
public string StockNumber { get; set; }
[System.Xml.Serialization.XmlElement("Make")]
public string Make { get; set; }
[System.Xml.Serialization.XmlElement("Model")]
public string Model { get; set; }
}
[Serializable()]
[System.Xml.Serialization.XmlRoot("CarCollection")]
public class CarCollection
{
[XmlArray("Cars")]
[XmlArrayItem("Car", typeof(Car))]
public Car[] Car { get; set; }
}
The Deserialize function:
CarCollection cars = null;
string path = "cars.xml";
XmlSerializer serializer = new XmlSerializer(typeof(CarCollection));
StreamReader reader = new StreamReader(path);
cars = (CarCollection)serializer.Deserialize(reader);
reader.Close();
And the slightly tweaked xml (I needed to add a new element to wrap ...Net is picky about deserializing arrays):
<?xml version="1.0" encoding="utf-8"?>
<CarCollection>
<Cars>
<Car>
<StockNumber>1020</StockNumber>
<Make>Nissan</Make>
<Model>Sentra</Model>
</Car>
<Car>
<StockNumber>1010</StockNumber>
<Make>Toyota</Make>
<Model>Corolla</Model>
</Car>
<Car>
<StockNumber>1111</StockNumber>
<Make>Honda</Make>
<Model>Accord</Model>
</Car>
</Cars>
</CarCollection>
Also take a look at
Loading custom configuration files
http://www.codeproject.com/Articles/32490/Custom-Configuration-Sections-for-Lazy-Coders
use the app config for your connectionStrings:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<connectionStrings>
<add name="MyDatabase" connectionString="......"/>
</connectionStrings>
</configuration>
add a reference to System.Configuration in your application and get the connection string via :
string connectionString = ConfigurationManager.ConnectionStrings["MyDatabase"].ConnectionString;
App.Config:
<configuration>
<connectionStrings>
<add name="connstring1"
connectionString="DataSource=123.123.123.123;UserID=XXX;Password=XXX;" />
</connectionStrings>
</configuration>
C# code:
var appConfig = ConfigurationManager.OpenExeConfiguration("your.exe");
string connectionstring = appConfig.ConnectionStrings.ConnectionStrings["connstring1"].ConnectionString;
You are trying to reinvent a wheel.
As people mentioned here, .config files are meant for application configuration. There is a dedicated section for connection strings in them, so you're advised to use it as it is standard and convenient.
Here is your config:
<configuration>
....
<connectionStrings>
<add name="OracleConnectionString" connectionString="providerName=system.data.oracleclient;User ID=****;password=****;Data Source=*****;Persist Security Info=True;Provider=OraOLEDB.Oracle;" providerName="System.Data.OracleClient" />
</connectionStrings>
</configuration>
and here is the code snippet to modify it:
string user = "Me";
string pwd = "qwerty";
Configuration cfg = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ConnectionStringsSection section = (ConnectionStringsSection)cfg.GetSection("connectionStrings");
var currentConnectionString = section.ConnectionStrings["OracleConnectionString"];
currentConnectionString.ConnectionString = string.Format("providerName=system.data.oracleclient;User ID={0};password={1};Data Source=*****;Persist Security Info=True;Provider=OraOLEDB.Oracle;", user, pwd);
cfg.Save();
ConfigurationManager.RefreshSection("connectionStrings");
Notes: 1. Be aware that you are saving .config in the /bin, not in your project folder, so when you rerun/redeploy your application, the changes will be discarded.
2. When debugging you won't see the changes as VS creates HOST process and copies a fresh .config file to the /bin. To see the changes you should run without debugging. Cheers.
Create a datatable with your values. do
Dt.WriteXml(fileName);
It will generate xml file. maintain this xml in future.
use Dt.ReadXml(filename) to get the values back in application.

XMLTextReader missing first element

I'm writing a configuration storage method for one of my clients and they requested that it be in XML. I've managed to get it to work other than one issue; the first element is missing. My XML file is:
<?xml version="1.0" encoding="utf-8" ?>
<config>
<username>test</username>
<password>pass</password>
<autologin>true</autologin>
</config>
My Parsing command is:
void parseConfigFile()
{
while (configstr.Read())
{
if (configstr.IsStartElement())
{
config.Add(configstr.Name,configstr.ReadString());
}
}
}
and the result (configstr) is:
autologin = true
config =
password = pass
var document = XDocument.Load("file.xml");
var config = document.Root;
var userName = (string)config.Element("username");
var password = (string)config.Element("password");
var autologin = (bool)config.Element("autologin");

Categories