C# XDocument Save copy file and appends edited to end - c#

When I'm trying to edit XML Element and save it, it generates copy (with edited element) and appends it to end of file.
var localStore = IsolatedStorageFile.GetUserStoreForApplication();
IsolatedStorageFileStream stream = new IsolatedStorageFileStream("DataFolder\\PlayerData.xml", FileMode.OpenOrCreate, FileAccess.ReadWrite, localStore);
var doc = XDocument.Load(stream);
doc.Root.Element("characters").Element("character").SetElementValue("expierence", 10);
doc.Save(stream, SaveOptions.None);
stream.Close();
Example output file:
<?xml version="1.0" encoding="utf-8"?>
<root>
<characters>
<character>
<expierence>0</expierence>
</character>
</characters>
</root><?xml version="1.0" encoding="utf-8"?>
<root>
<characters>
<character>
<expierence>10</expierence>
</character>
</characters>
</root>

That's exactly what you told it to do by passing FileMode.OpenOrCreate.
If you want to truncate any existing file, pass Create.
For more information, see the documentation.

Related

How to get encoding of xml file?

How to get the information of encoding in a xml file using c#?
<?xml version="1.0" encoding="iso-8859-1"?>
<?xml version="1.0" encoding="Windows-1252"?>
I know how to read in the elements and attributes...
But I have to make a definition by cases in my deserialization method:
Depending on the encoding type of the xml I have to use encoding_windows or encoding_utf for StreamReader
var encoding_windows = Encoding.GetEncoding("Windows-1252");
var encoding_utf = Encoding.GetEncoding("utf-8");
var sr = new StreamReader(current_file, encoding_windows, true);
As your are using StreamReader try this :
var sr = new StreamReader(current_file);
var encodingCurrentFile = sr.CurrentEncoding.EncodingName;
Console.WriteLine(encodingCurrentFile);
encodingCurrentFile is your current encoding name.

How to remove xml element in windows phone

After I could create an xml, and adding data and element to it, I want to be able to remove a specific element from it as well. I tried to follow what it said from here Deleting XML element nodes, then I could be able to remove any element from it; however, it does not remove that element completely; therefore, it's producing an error to my xml file.
My sample xml is like this (before removing)
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!--Favorite's xml-->
<favorites>
<favorite id="1" pro_id="1" pro_name="Boots Expert Anti-Blemish Cleansing Foam" cate_xml="ProductsOily.xml" pro_image="images/Oily-Dry/BO001.JPG" />
<favorite id="2" pro_id="2" pro_name="Clean & Clear Advantage Oil Absorbing Cream Cleanser" cate_xml="ProductsOily.xml" pro_image="images/Oily-Dry/BP251.jpg" />
</favorites>
From example, I tried to remove an element that has pro_id equals 1, but my xml file, after remove, became like this
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!--Favorite's xml-->
<favorites>
<favorite id="2" pro_id="2" pro_name="Clean & Clear Advantage Oil Absorbing Cream Cleanser" cate_xml="ProductsOily.xml" pro_image="images/Oily-Dry/BP251.jpg" />
</favorites>" pro_name="Clean & Clear Advantage Oil Absorbing Cream Cleanser" cate_xml="ProductsOily
Here is my code to do this:
var storage = IsolatedStorageFile.GetUserStoreForApplication();
fileName = "Favorite\\Favorite.xml";
XDocument docx = null;
using (IsolatedStorageFileStream isoStreamx = new IsolatedStorageFileStream(fileName, FileMode.Open, storage))
{
// isoStreamx.Position = 0;
docx = XDocument.Load(isoStreamx);
isoStreamx.SetLength(docx.ToString().Length);
docx.Root.Elements().Where(x => x.Attribute("pro_id").Value == NavigationContext.QueryString["id"] as string).Remove();
isoStreamx.Position = 0;
docx.Save(isoStreamx);
}
How can I completely remove an element? Please help me, thanks.
You're currently reusing the same stream to save over the top. That will only overwrite data - it won't truncate the file at the end point of your document. What you really want to do is effectively create a new file. Something like:
var storage = IsolatedStorageFile.GetUserStoreForApplication();
fileName = "Favorite\\Favorite.xml";
XDocument docx = null;
using (var isoStreamx = new IsolatedStorageFileStream(fileName, FileMode.Open, storage))
{
docx = XDocument.Load(isoStreamx);
}
var target = (string) NavigationContext.QueryString["id"];
docx.Root
.Elements()
.Where(x => x.Attribute("pro_id").Value == target)
.Remove();
using (var isoStreamx = new IsolatedStorageFileStream(fileName, FileMode.Create, storage))
{
docx.Save(isoStreamx);
}
You could keep your current code, and just call isoStreamx.SetLength(isoStreamx.Position) at the end (removing the current pointless and broken SetLength call) - but I think it's cleaner to use the code above.

Why does overwriting an XML file create an extra end tag?

I am creating an application in C# that has to write some user settings to an XML file. They are read perfectly fine, but when I try to write them back they create an extra end tag that the program cannot read.
XML file:
<?xml version="1.0" encoding="utf-8" ?>
<options>
<fullscreen>False</fullscreen>
<resolutionX>1280</resolutionX>
<resolutionY>720</resolutionY>
<vsync>True</vsync>
<AA>2</AA>
<musicvolume>0</musicvolume>
<soundvolume>0</soundvolume>
</options>
Code that writes:
FileStream stream =
new FileStream("configs/options.xml", FileMode.Open, FileAccess.ReadWrite);
XmlDocument doc = new XmlDocument();
doc.Load(stream);
stream.Seek(0, SeekOrigin.Begin);
doc.SelectSingleNode("/options/fullscreen").InnerText = fullscreen.ToString();
doc.SelectSingleNode("/options/vsync").InnerText = vsync.ToString();
doc.SelectSingleNode("/options/resolutionX").InnerText = resolutionX.ToString();
doc.SelectSingleNode("/options/resolutionY").InnerText = resolutionY.ToString();
doc.SelectSingleNode("/options/AA").InnerText = aa.ToString();
doc.SelectSingleNode("/options/musicvolume").InnerText = musicvolume.ToString();
doc.SelectSingleNode("/options/soundvolume").InnerText = soundvolume.ToString();
doc.Save(stream);
stream.Close();
What I end up with:
<?xml version="1.0" encoding="utf-8" ?>
<options>
<fullscreen>True</fullscreen>
<resolutionX>1280</resolutionX>
<resolutionY>720</resolutionY>
<vsync>True</vsync>
<AA>4</AA>
<musicvolume>0</musicvolume>
<soundvolume>0</soundvolume>
</options>/options>
Since you’re writing to the same stream, if the modified XML is shorter than the original, the difference will remain. You can use FileStream.SetLength after saving to fix that:
doc.Save(stream);
stream.SetLength(stream.Position);
stream.Close();

Insert XML file into existing XML file using LINQ to XML

Using some example code I found here on SO, I've put together a bit of code to open up an existing XML database, open up another XML file that's to be inserted into the first XML, get the descendants of the root node in that file, and append them to the base of the selected node in the database.xml file, and then save the resultant file to a new XML file. The code below compiles & runs with no errors in VS2010, but doesn't add the XML from the actionID.xml file to the database.xml file and I don't know what I'm missing.
Here's the C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
class pcbdbUpdate
{
static void Main( )
{
//open database & load into memory
XDocument PCBDB = XDocument.Load("C:\\database.xml");
//open Activity Log file & load into memory
XDocument addAction = XDocument.Load("C:\\actionID.xml");
//get descendant node(s) below PCBDBActivityLog root node
var actionXML = addAction.Root.Descendants("PCBDBActivityLog");
/*supposed to write out child nodes, but not very useful, just tells me
it's a: System.Xml.Linq.XContainer+<GetDescendants>d__a*/
Console.WriteLine(actionXML.ToString());
//enumerate database for SBE_PCB_Data nodes
IEnumerable<XElement> SBE_PCB_Data = PCBDB.Element("PCBDatabase").Elements("SBE_PCB_Data");
//look for specific node with PCBID of "00001" and select it
XElement newAction = SBE_PCB_Data.Where(p => p.Attribute("PCBID").Value == "00001").FirstOrDefault();
//write descendants from Activity Log to base of node
newAction.Add(actionXML);
//save the resultant file
PCBDB.Save("C:\\newDatabase.xml");
}
}
Here's the database.xml:
<?xml version="1.0" encoding="utf-8"?>
<PCBDatabase>
<SBE_PCB_Data PCBID="00001">
<Creation ActionID="0002" User="DELLIOTTG:192.168.1.69" Date="2012-10-31T14:35:58" PCBID="00001">
<PCBDrawing>00001a</PCBDrawing>
<AssemblyDrawing>00001b</AssemblyDrawing>
<Vendor>SBE</Vendor>
<PONumber>00000</PONumber>
</Creation>
<Assignment ActionID="1295" User="RHO:192.168.1.6" Date="2012-12-13T08:59:31" PCBID="00001">
<PCBDrawing>00002a</PCBDrawing>
<AssemblyDrawing>00001c</AssemblyDrawing>
<Vendor>SBE</Vendor>
<PONumber>00001</PONumber>
</Assignment>
</SBE_PCB_Data>
<SBE_PCB_Data PCBID="00002">
<Assignment ActionID="630c" User="DMUELLER:192.168.1.152" Date="2010-03-15T13:14:21" PCBID="00002">
<SBEJobNumber>57380</SBEJobNumber>
</Assignment>
</SBE_PCB_Data>
</PCBDatabase>
And here's the actionID.xml:
<?xml version="1.0"?>
<PCBDBActivityLog>
<Assignment ActionID='8353' User='DMUELLER:192.168.1.134' Date='2011-01-27T15:38:25' PCBID='00001'>
<SBEPN>41528E</SBEPN>
</Assignment>
</PCBDBActivityLog>
The resultant file should look like this:
<?xml version="1.0" encoding="utf-8"?>
<PCBDatabase>
<SBE_PCB_Data PCBID="00001">
<Creation ActionID="0002" User="DELLIOTTG:192.168.1.69" Date="2012-10-31T14:35:58" PCBID="00001">
<PCBDrawing>00001a</PCBDrawing>
<AssemblyDrawing>00001b</AssemblyDrawing>
<Vendor>SBE</Vendor>
<PONumber>00000</PONumber>
</Creation>
<Assignment ActionID="1295" User="RHO:192.168.1.6" Date="2012-12-13T08:59:31" PCBID="00001">
<PCBDrawing>00002a</PCBDrawing>
<AssemblyDrawing>00001c</AssemblyDrawing>
<Vendor>SBE</Vendor>
<PONumber>00001</PONumber>
</Assignment>
<Assignment ActionID='8353' User='DMUELLER:192.168.1.134' Date='2011-01-27T15:38:25' PCBID='00001'>
<SBEPN>41528E</SBEPN>
</Assignment>
</SBE_PCB_Data>
<SBE_PCB_Data PCBID="00002">
<Assignment ActionID="630c" User="DMUELLER:192.168.1.152" Date="2010-03-15T13:14:21" PCBID="00002">
<SBEJobNumber>57380</SBEJobNumber>
</Assignment>
</SBE_PCB_Data>
</PCBDatabase>
What am I missing or doing wrong?
Error is here:
var actionXML = addAction.Root.Descendants("PCBDBActivityLog")`
You are trying to find <PCBDBActivityLog> elements under the document root. But this will return nothing, because <PCBDBActivityLog> element is a root of actionID.xml document. Replace this line with
var actionXML = addAction.Descendants("PCBDBActivityLog");
Or
var actionXML = addAction.Root;

Add a Text line in xml on a particular location?

How can I insert the following stylesheet information into my existing xml file which is created using C#?
<?xml-stylesheet type="text/xsl" href="_fileName.xsl"?>
Or.... Can I add this line at the time of creation of the new XML file?
Edit:
I tried to achieve the above using XmlSerialier (hit and trial), something like this:
// assumes 'XML' file exists.
XmlDocument doc = new XmlDocument();
XElement dataElements = XElement.Load("_fileName.xml");
XmlSerializer xs = new XmlSerializer(typeof(Parents));
var ms = new MemoryStream();
xs.Serialize(ms, parents);
ms.Seek(0, SeekOrigin.Begin); // rewind stream to beginning
doc.Load(ms);
XmlProcessingInstruction pi;
string data = "type=\"text/xsl\" href=\"_fileName.xsl\"";
pi = doc.CreateProcessingInstruction("xml-stylesheet", data);
doc.InsertBefore(pi, doc.DocumentElement); // insert before root
doc.DocumentElement.Attributes.RemoveAll(); // remove namespaces
But the output xml is getting corrupted:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="_fileName.xsl"?>
<parents />
Whereas the desired output is something like:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="_fileName.xsl"?>
<parents>
<parent>
<Child1>
<child2>
</parent>
</parents>
Did this help to understand what's my problem???
You didn't answer the question.. "what lib do you use".
Although I advise:
XDocument
if you would use it you could do something like:
XDocument document = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));
document.Add(new XProcessingInstruction(
"xml-stylesheet", "type=\"text/xsl\" href=\"_fileName.xsl\""));
//and then your actual document...
document.Add(
new XElement("parent",
new XElement("child1"),
new XElement("child2")
)
);
EDIT:
Ok So you could do it like:
XDocument document = XDocument.Load("file");
document.AddFirst(new XProcessingInstruction(
"xml-stylesheet", "type=\"text/xsl\" href=\"LogStyle.xsl\""));
Is this what you're looking for?

Categories

Resources