How to get specific attributes from all xml files in directory? - c#

I have a folder full of xml files. In these files many of them share a common attribute (Name), but have a secondary attribute that is different. I want to get a list of the unique entries based off reading these xml files. Below is an example of what the various xml files will contain.
File 1
<?xml version="1.0" encoding="UTF-8"?>
<results date="2013-12-29">
<A uniqueId="1234" Name="My-Machine"/>
<error number="555">
<description><![CDATA[House on Fire]]></description>
</error>
</results>
File 2
<?xml version="1.0" encoding="UTF-8"?>
<results date="2013-12-29">
<A uniqueId="1234" Name="My-Machine"/>
<error number="556">
<description><![CDATA[House in flood]]></description>
</error>
</results>
File 3
<?xml version="1.0" encoding="UTF-8"?>
<results date="2013-12-29">
<A uniqueId="1234" Name="My-Machine"/>
<error number="556">
<description><![CDATA[House in flood]]></description>
</error>
</results>
I need to be able to read all the files, add each Name and description to a list (or possibly array). Output from example would look like this:
Name="MyMachine", description="![CDATA[House is flooding]]";
Name="MyMachine", description="![CDATA[House on fire]]";
Name="MyMachine", description="![CDATA[House on fire]]";
It seems LINQ may be the best way to handle this since the files are very small in content.

Here is a way to read that description element content from one file:
var xDoc = XDocument.Load("Input.xml");
var name = "My-Machine";
var aElement = xDoc.Root.Element("A");
string description = null;
if ((string)aElement.Attribute("Name") == name)
description = (string)xDoc.Root.Element("error").Element("description");
It will return the element value when Name attribute value matches your name variable. Otherwise description will be null.

Related

How to read a value from a xml file

I have the following XML File,
<?xml version="1.0"?>
<MainClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Items>
<Settings xsi:type="FileModel">
<Name>FileRepository</Name>
<IsActive>true</IsActive>
<IsHidden>false</IsHidden>
</Settings>
<Settings xsi:type="ServerModel">
<Name>DelRep</Name>
<IsActive>false</IsActive>
<IsHidden>false</IsHidden>
</Settings>
</Items>
<DirectoryPath>D:\MainFolder</DirectoryPath>
</MainClass>
This XML File stored above in a string as string wholeContent = File.ReadAllText(this.FilePath);
where this FilePath has a valid path to the location of the file .
the wholeContent stores the entire XML which I later use but now I have the necessity to obtain the path stores as a string within the <DirectoryPath> . Is there a way I can do this using wholeContent or what would be the appropriate approach ?
I would recommend not to load the XML document as string, use the types provided by .NET, such as XDocument.
Accessing the elements and their values gets very easy that way:
XDocument document = XDocument.Load(this.FilePath);
var element = document.Root.Elements().Single(x => x.Name == "DirectoryPath");
var directoryPath = element.Value;

Get value of an Xml attribute using Linq to Xml

I have an XML like this:
<?xml version="1.0" encoding="utf-8"?>
<Projects>
<Project>
<Name>Projekt0</Name>
<Information>
<Version>1.0</Version>
<Info>test-project</Info>
<CreateDate>25.02.2015</CreateDate>
</Information>
<Files ID="1" path="D:\Data\ID1">
<file>one_file</file>
<file>another_file</file>
</Files>
<Files ID="2" path="D:\Data\ID2">
<file>someFile.txt</file>
</Files>
</Project>
</Projects>
It contains some more "Project"-Nodes, but that's not necessary.
First, I select a specific project by it's name. This works already, and is done this way:
var entries = from items in xelement.Elements("Project")
where (string)items.Element("Name").Value == projectName
select items;
entries contains now all the content of the wanted project.
One of my methods need to know the path-values of the both "Files"-Nodes.
I already tried something, but it's not working yet.
My first try was creating a new 'var' like 'entries', converting that to an array, and selecting the indices for saving the values as a string.
var path1 = from item in entries.Elements("Files")
where (string)item.Attribute("ID").Value == "1"
select item.Attribute("path").Value;
string path01 = path1.toArray()[0];
That is not working, and I'm not sure why. I'm sorry if that is a beginners question, but I haven't done a lot with xml & linq yet.
edit:
The lower 'entries' variable is the output of the first linq-code. So 'entries' contains a whole project.
Currently, path1 does not contain any elements.
entries is a sequence of Project nodes. Take Files child nodes before searching ID attribute
var path1 = from item in entries.Elements("Files")
where (string)item.Attribute("ID").Value == "1"
select item.Attribute("path").Value;

export list of object to xml file in c#

I try to export a list of object(type of "Doctor") to an xml file in c#.
It compiles and runs, but the file I get isn't correct. Can someone please can tell me what I did incorrect?
the code is:
public static void exportAsXml(string fileName, List<Entity> ListOfEntity)
{
FileInfo file = new FileInfo(fileName + ".xml");
StreamWriter sw = file.AppendText();
System.Xml.Serialization.XmlSerializer writer = new System.Xml.Serialization.XmlSerializer(typeof(Doctor));
foreach (Entity e in ListOfEntity)
{
writer.Serialize(sw,e as Doctor);
}
sw.Close();
}
the xml file is:
<?xml version="1.0" encoding="utf-8"?>
<Doctor xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ID>87587579</ID>
<FirstName>Dan</FirstName>
<LastName>Adi</LastName>
<Gender>male</Gender>
<Salary>15000</Salary>
</Doctor><?xml version="1.0" encoding="utf-8"?>
<Doctor xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ID>302342246</ID>
<FirstName>Lital</FirstName>
<LastName>Gal</LastName>
<Gender>female</Gender>
<Salary>25600</Salary>
</Doctor><?xml version="1.0" encoding="utf-8"?>
<Doctor xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ID>205992457</ID>
<FirstName>Yaron</FirstName>
<LastName>Mor</LastName>
<Gender>male</Gender>
<Salary>10000</Salary>
</Doctor>
Thanks!
First of all, the resulting xml violates 2 core rules.
Xml file should have only one <?xml version="1.0" encoding="utf-8"> declaration
All your xml should be enclosed inside one root file.
In other words, in loop you generate a separate, fully-fledged xml file for each item.
Try this
var writer = new System.Xml.Serialization.XmlSerializer(typeof(List<Doctor>));
writer.Serialize(sw, ListOfEntity);
You are corrupting the xml file by serializing the doctor objects and saving it to the same file using file.AppendText();, generating corrupted xml with multiple <?xml version="1.0" encoding="utf-8"?> declarations as consequence.
You should serialize the List<Doctor> instead of serializing each doctor alone and modifying the xml file by appending text.
If you want to modify a serialized object saved inside a file, you need to deserialize the file into an object, modify it and then replace the file with the new serialized object. you cannot simply append it.

Incorrect structured XML document after deleting element

When I try to load a XML file after deleting an Element from the file, it shows the following error: Unexpected XML declaration. The XML declaration must be the first node in the document, and no white space characters are allowed to appear before it. Line 9, position 10. What is wrong with my code?
This is my XML file:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<booze>booze1</booze>
<booze>booze2</booze>
<booze>booze3</booze>
<booze>booze4</booze>
</data>
And my code:
using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream("favorites.xml", FileMode.Open, file))
{
XDocument xDoc = XDocument.Load(stream, LoadOptions.None);
// delete node
xDoc.Descendants("data").Elements("booze").Where(x => x.Value == favorite).DescendantsAndSelf().Remove();
xDoc.Save(stream);
}
}
My guess is that when you run the code for the first time, the delete succeeds and your XDoc contains :
<?xml version="1.0" encoding="utf-8"?>
<data>
<booze>booze1</booze>
<booze>booze2</booze>
<booze>booze4</booze>
</data>
, but when calling XDoc.Save you simply append this to the favorites.xml file. After that, the favorites.xml file contains something like this:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<booze>booze1</booze>
<booze>booze2</booze>
<booze>booze3</booze>
<booze>booze4</booze>
</data><?xml version="1.0" encoding="utf-8"?>
<data>
<booze>booze1</booze>
<booze>booze2</booze>
<booze>booze4</booze>
</data>
That is why all the subsequent file loads throw the error. What you should do is overwrite the file, and not append to it. The first way of doing that that comes to mind is to close the stream, open it with Mode.Truncate and then save the XDoc. Or you can delete and recreate the file. I am not that familiar with IsolatedStorageFiles so this is a wild guess.

umbraco.library get nodename but string utf-8 show wrong

I get nodename like this:
string text = umbraco.presentation.nodeFactory.Node.GetCurrent().Name;
but it shows like this:
BETON KÖÅÂÂK
How can I solve it?
GetCurrent().Name should return a string
(http://our.umbraco.org/wiki/reference/api-cheatsheet/working-with-nodefactory)
So if your string looks like that either your encoding is not set to utf-8 or your App_Data\umbraco.config file is corrupt.
The NodeFactory methods are basically a facade in front of the umbraco.config file - so have a look in that file to see if it is corrupted. The umbraco.config file is an xml file so also check that the first line is:
<?xml version="1.0" encoding="utf-8"?>
Secondly check your web.config for the encoding:
<system.web>
<globalization requestEncoding="UTF-8" responseEncoding="UTF-8"/>
Thirdly check all your Umbraco \config*.config files (which are all xml files) and make sure that the first line is:
<?xml version="1.0" encoding="utf-8"?>

Categories