How to use Linq to XML to override existing XML file - c#

I have a simple XML file structured like this
<?xml version="1.0" encoding="utf-8" ?>
<event>
<name>Test Event</name>
<date>06/09/1990</date>
<description>Birthday</description>
<blogURL></blogURL>
</event>
What I am trying to achieve is to have a form accept user input to create a new XML document with the same structure that will overwrite the old one.
The XML document is in the same directory as the ASPX page that will accept the input.
When the user navigates to the PressRelease.aspx page, it loads the values in the document.
var doc = XDocument.Load(Server.MapPath("~/PressSection.xml"));
string currentEventName = (string)doc.Descendants("name").Single();
string currentEventDate = (string)doc.Descendants("date").Single();
string currentEventDescription = (string)doc.Descendants("description").Single();
string currentEventLink = (string)doc.Descendants("blogURL").Single();
if (currentEventLink.ToString() == "")
{
CurrentEventURL.Text = "This event has no URL";
}
CurrentEventName.Text = currentEventName;
CurrentEventDescription.Text = currentEventDescription;
CurrentEventDate.Text = currentEventDate;
This works. I am grabbing the user input and doing simple validation like this
string newEventName = NewEventName.Text;
string newEventDescription = NewDescription.Text;
string newEventDate = NewDate.SelectedDate.Value.Date.ToString();
string newEventURL = NewURL.Text;
if (newEventName == "")
{
MessageBox.Text = "Please enter a valid event name";
MessageBox.CssClass = "event_error";
return;
}
if (newEventDescription == "")
{
MessageBox.Text = "Please enter a valid description";
MessageBox.CssClass = "event_error";
return;
}
if (newEventDate == null)
{
MessageBox.Text = "Please select a valid date";
MessageBox.CssClass = "event_error";
return;
}
And finally, I build and save the new XML document like this
//Create new document
XDocument newEventDocument = new XDocument(new XDeclaration("1.0", "utf-8", null));
//Addd root node
XElement RootNode = new XElement("Event");
//add root node to new document
newEventDocument.Add(RootNode);
//Add event name element then add it to the new document
XElement eName;
eName = new XElement("name");
eName.Value = newEventName;
newEventDocument.Root.Add(eName);
//Add event date element then add it to the new document
XElement eDate;
eDate = new XElement("date");
eDate.Value = newEventDate;
newEventDocument.Root.Add(eDate);
//Add event description element then add it to the new document
XElement eDescription;
eDescription = new XElement("description");
eDescription.Value = newEventDescription;
newEventDocument.Root.Add(eDescription);
//Add event URL element then add it to the new document
XElement eURL;
eURL = new XElement("blogURL");
eURL.Value = newEventURL;
newEventDocument.Root.Add(eURL);
//Finally, save the document
newEventDocument.Save("PressSection.xml", SaveOptions.None);
The issue that my program throws is an invalid permissions problem.
Access to the path 'C:\Program Files (x86)\IIS Express\PressSection.xml' is denied.
My question is, how do I save this in the root of my project directory, instead of IN MY IIS Express folder? I need it to overwrite the existing 'PressSection.xml' file that already exists in my project. Thanks!

This worked for it. Sorry for such an easy question
string path = Server.MapPath("PressSection.xml");
newEventDocument.Save(Path.Combine(path));

Related

Remove Node from XmlSerializer

I want to save a WCF request as file to a catalog, but when the file(xml) is created from the XmlSerializer it adds a Node to the XML file which I do not want. Called ("ProjectInRequest"). I do not want to have this node in the created output file.
How can I remove it in the most sufficent way?
I have tried to load the whole document in XmlDocument where the file should be created, but the creation of the file does not happen until the response is returned. There fore the whole service fails.
namespace SymbrioProjectIn
{
public partial class SymbrioProjectIn_v1
{
public ProjectInResponse GetSymbrioProjectInRequest(ProjectInRequest request)
{
if (request == null || request.SymbrioXMLProjectIn.Project == null && request.SymbrioXMLProjectIn.Routing == null )
{
throw new ApplicationException("Request is null: You need to send info in request.");
}
else
{
try
{
//All we want to do is take the Request that SAP sends and store it to a file catalog.
//We can after that use BizTalk to move the file too another sftp catalog for Symbrio
string path = AppDomain.CurrentDomain.BaseDirectory;
String dir = Path.GetDirectoryName(path);
dir += "\\ProjectIn_Data";
string filename = dir + "\\ProjectIn.xml";
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir); // inside the if statement
//XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
//Add an empty namespace and empty value
//ns.(string.Empty, string.Empty);
//XElement ProjectInRequest = new XElement("ProjectInRequest");
//ProjectInRequest.RemoveAll();
/*XmlAttributes ignore = new XmlAttributes() { XmlIgnore = true };
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
overrides.Add(typeof(ProjectInRequest), "ProjectInRequest", ignore);*/
XmlSerializer ser = new XmlSerializer(request.GetType(), new XmlRootAttribute("ProjectInRequest").ElementName); //Tried som code from internet not sure what it does
FileStream fs = File.Open(
filename,
FileMode.OpenOrCreate,
FileAccess.Write,
FileShare.ReadWrite);
ser.Serialize(fs, request);
var response = new SymbrioProjectIn.ProjectInResponse{
SymbrioXMLProjectIn = request.SymbrioXMLProjectIn
};
//Looks like xmlSerialiser creates some type of namespace which I do not want.
//Create our own namespaces for the output
XmlDocument XDoc = new XmlDocument();
XDoc.Load(#"D:\ServiceArea\SymbrioProjectIn\ProjectIn_Data\ProjectIn.xml");
XmlNodeList RemoveNodeProjectInRequest = XDoc.GetElementsByTagName("ProjectInRequest");
foreach (XmlNode Node in RemoveNodeProjectInRequest)
{
Node.ParentNode.RemoveChild(Node);
}
XDoc.Save(#"D:\ServiceArea\SymbrioProjectIn\ProjectIn_Data\ProjectIn.xml");
return response;
}
catch (Exception ex)
{
//throw new Exception(ex.Message);
throw new ApplicationException(ex.Message);
}
}
}
}
}
The file that is created looks like this
<?xml version="1.0"?>
<ProjectInRequest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="ProjectInRequest">
<SymbrioXMLProjectIn>
<Routing SourceValue="?" SourceType="?" DestinationValue="?" DestinationType="?" xmlns="http://www.symbrio.com/schemas/symbrioprojectin20133" />
<Project xmlns="http://www.symbrio.com/schemas/symbrioprojectin20133">
<CompanyCode>?</CompanyCode>
<DivisionCode>?</DivisionCode>
<MainProjectNo>?</MainProjectNo>
<ProjectNo>?</ProjectNo>
<ProjectName>?</ProjectName>
<ProjectType>?</ProjectType>
<PLCode>?</PLCode>
<EmploymentNo>?</EmploymentNo>
<Active>?</Active>
<ActiveStart>?</ActiveStart>
<ActiveEnd>?</ActiveEnd>
<DeliveryAddress>?</DeliveryAddress>
<DeliveryPostalCode>?</DeliveryPostalCode>
<DeliveryCity>?</DeliveryCity>
<DeliveryAddressNoteText>?</DeliveryAddressNoteText>
<AccountRef1>?</AccountRef1>
<AccountRef2>?</AccountRef2>
<AccountRef3>?</AccountRef3>
<AccountRef4>?</AccountRef4>
<RegisteredDate>?</RegisteredDate>
<Closed>?</Closed>
</Project>
</SymbrioXMLProjectIn>
</ProjectInRequest>
What I want is this,
<?xml version="1.0" encoding="utf-8"?>
<SymbrioXMLProjectIn>
<Routing SourceValue="str1234" SourceType="str1234" DestinationValue="str1234" DestinationType="str1234" />
<Project>
<CompanyCode>str1234</CompanyCode>
<DivisionCode>str1234</DivisionCode>
<MainProjectNo>str1234</MainProjectNo>
<ProjectNo>str1234</ProjectNo>
<ProjectName>str1234</ProjectName>
<ProjectType>str1234</ProjectType>
<PLCode>str1234</PLCode>
<EmploymentNo>str1234</EmploymentNo>
<Active>str1234</Active>
<ActiveStart>str1234</ActiveStart>
<ActiveEnd>str1234</ActiveEnd>
<DeliveryAddress>str1234</DeliveryAddress>
<DeliveryPostalCode>str1234</DeliveryPostalCode>
<DeliveryCity>str1234</DeliveryCity>
<DeliveryAddressNoteText>str1234</DeliveryAddressNoteText>
<AccountRef1>str1234</AccountRef1>
<AccountRef2>str1234</AccountRef2>
<AccountRef3>str1234</AccountRef3>
<AccountRef4>str1234</AccountRef4>
<RegisteredDate>str1234</RegisteredDate>
<Closed>str1234</Closed>
</Project>
</SymbrioXMLProjectIn>
ProjectInRequest - Node does not exist.
I might have missed something if so please point it out.
Thanks in advance.
use xpath to extract the record you wanted
//*[local-name()='SymbrioXMLProjectIn']
Nvm found the solution, I XmlSeralized wrong the correct way should have been
XmlSerializer ser = new XmlSerializer(request.SymbrioXMLProjectIn.GetType());
the bad way was
XmlSerializer ser = new XmlSerializer(request.GetType());
Will leave this here if anyone does a dummy misstake like me.

How to add more than one user to an xml file

I'm new to C# and currently trying to create a simple login screen using windows forms. The program takes the forms input and saves the username and password to an XML file. I'm just wondering how I can save more than one user instead of the previous users data being overwritten when I save a new user. This is the code I'm currently using.
{
XmlTextWriter write = new XmlTextWriter("XML.xml", Encoding.UTF8);
write.WriteStartElement("USER");
write.WriteStartElement("username");
write.WriteString(textBox1.Text);
write.WriteEndElement();
write.WriteStartElement("passsword");
write.WriteString(textBox2.Text);
write.WriteEndElement();
write.WriteEndElement();
write.Close();
}
Try this:
XmlDocument xmlDoc = new XmlDocument();
string filePath = Path.Combine(#"C:\assets\" + "users.xml");
XmlNode usersNode;
if (File.Exists(filePath))
{
xmlDoc.Load(filePath);
usersNode = xmlDoc.SelectSingleNode(#"Users");
}
else
{
usersNode = xmlDoc.CreateElement("Users");
xmlDoc.AppendChild(usersNode);
}
XmlElement user = xmlDoc.CreateElement("User");
XmlElement userName = xmlDoc.CreateElement("UserName");
XmlElement pass = xmlDoc.CreateElement("Pass");
userName.InnerText = "TestUser";
pass.InnerText = "TemPass";
user.AppendChild(userName);
user.AppendChild(pass);
usersNode.AppendChild(user);
xmlDoc.Save(filePath);

c# xml look for node with / in title

I've got a WFA running which takes an XML file and "prettifys" it.
what I would like to add now is a check to see if a specific node exists, and if not , display a message.
the XML looks like
<message>
<success/>
<bookings>
Some extra nodes I need not look for at this time
</bookings>
</message>
what I am (unsuccessfully) trying to do it to look for the existence of
<success/>
and if not found, display a message.
The code I have be trying to do this with is
InitializeComponent();
openFileDialog1.FileName = String.Empty; //blank filename
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
richTextBox1.LoadFile(openFileDialog1.FileName, RichTextBoxStreamType.PlainText);
XmlDocument doc = new XmlDocument();
doc.Load(openFileDialog1.FileName);
XmlNodeList nodeToFind = doc.GetElementsByTagName("success/");
if (nodeToFind != null)
{
richTextBox2.AppendText("node found");
}
this did not work, so I tried it by doing a .Count on nodeToFind, and loading the value into a VAR (called Successful) and then amending the If to
if (Successful !=0) {
display a message
}
but that only comes back with 0 each time.
I am guessing that the it might be the / in the node name.
can anyone help ?
thanks
EDIT:
WORKING CODE now looks like
InitializeComponent();
openFileDialog1.FileName = String.Empty; //blank filename
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
richTextBox1.LoadFile(openFileDialog1.FileName, RichTextBoxStreamType.PlainText);
XmlDocument doc = new XmlDocument();
doc.Load(openFileDialog1.FileName);
XmlNodeList nodeToFind = doc.GetElementsByTagName("success");
int Successfull = nodeToFind.Count;
if (Successfull == 0)
{
richTextBox2.AppendText("node NOT found");
}
}
thanks #SLaks
That's a self-closing tag (equivalent to <success></success>).
The / is not part of the name.

C# xmlReader simple XML

I've got simple XML like:
<?xml version="1.0" encoding="utf-8"?>
<ftp>
<address>ftp://ftp.example.com/</address>
<user>jondoe</user>
<password>Password123</password>
</ftp>
And I wanted to use this C# code:
using (XmlReader reader = XmlReader.Create(xmlPath))
{
reader.ReadToFollowing("address");
string ftpAddress = reader.ReadElementContentAsString();
reader.ReadToFollowing("user");
string ftpUser = reader.ReadElementContentAsString();
reader.ReadToFollowing("password");
string ftpPw = reader.ReadElementContentAsString();
}
It's working fine when I want to read only one content, like address but it fails when I want to read more/next ones. I thought this would be logical but it seems like it's not. How to read that XML and all elements of it: address, user and password? I would like to use XmlReader for that.
The simplest form I can think of would be this one:
XElement xml = XElement.Parse(File.ReadAllText(xmlPath));
var ftpAddress = xml.Element("address").Value;
var ftpUser = xml.Element("user").Value;
var ftpPwd = xml.Element("user").Value;
Of course you should add some safety by checking for null values and if the file exists..
Update:
I would implement a failsafe version this way:
if (!File.Exists(xmlPath))
throw new FileNotFoundException(string.Format("The FTP configuration file {0} is missing", xmlPath));
XElement xml = XElement.Parse(File.ReadAllText(xmlPath));
var ftpAddress = GetConfigValue(xml, "address");
var ftpUser = GetConfigValue(xml, "user");
var ftpPwd = GetConfigValue(xml, "password");
With GetConfigValue like this:
private static string GetConfigValue(XContainer parent, XName name)
{
var element = parent.Element(name);
if (element == null)
throw new ArgumentException(string.Format("Invalid configuration file, missing element {0}", name));
return element.Value;
}

Writing to XML using XDocument, but knowing where to write

Hope you can help me a bit. I'm trying to write to an XML file, but am struggling to write the method which, well, writes to the XML file. This is the XML file manually written (using Notepad++ etc.):
<software>
<software_entry
name="Adobe Acrobat X Standard"
path="Applications\Acrobat\Acrobat X Standard\AcroStan.msi"
type="msi"
switches="/qn ALLUSERS=1"
/>
<software_entry
name="Adobe Acrobat X Professional"
path="Applications\Acrobat\Acrobat X Pro\AcroPro.msi"
type="msi"
switches="/qn ALLUSERS=1"
/>
</software>
The aim of this part of the application is to write that using a GUI.
In the application, the user chooses the name of the XML file. It is then saved in the temp folder until further in the process when the user is asked where they would like to save it. Upon entering the desired name of the file and clicking Create, the method called "createAndLoadXML" is run. As its name would suggest, it creates and then loads an XML file (to populate a listview control on the form). Code can be seen below.
private void createAndLoadXML()
{
// Method to create XML file based on name entered by user
string tempPath = Path.GetTempPath();
string configFileName = fileNameTextBox.Text;
string configPath = tempPath + configFileName + ".xml";
// Create XDocument
XDocument document = new XDocument(
new XDeclaration("1.0", "utf8", "yes"),
new XComment("This XML file defines the software selections for use with the Software Installer"),
new XComment("XML file generated by Software Installer"),
new XElement("software",
new XElement("software_entry",
new XAttribute("name", ""),
new XAttribute("path", ""),
new XAttribute("type", ""),
new XAttribute("switches", ""))
)
);
document.Save(configPath);
configCreateLabel.Visible = true;
document = XDocument.Load(configPath);
}
Now, further down this form are 4 text boxes for user input, each relating to the attributes created (name, path, type and switches) The idea is the user will write in these text boxes, click an 'Add' button and then the program will write those 4 fields as attributes to this XML file. So far, I have this code, which is horribly incomplete and doesn't even use LINQ to XML.
private void writeToXML()
{
// Method to write lines to XML file based on user input
// Sets string variables
string fileName = softwareNameTextBox.Text;
string filePath = filePathTextBox.Text;
string fileType = installerType.Text.ToString();
string installSwitches = installSwitchesTextBox.Text;
using (XmlWriter xw = XmlWriter.Load(configPath)) //This line is wrong, I know
{
xw.WriteStartElement("software");
xw.WriteElementString("name", fileName);
xw.WriteElementString("path", filePath);
xw.WriteElementString("type", fileType);
xw.WriteElementString("switches", installSwitches);
xw.WriteEndElement();
}
}
Basically, could anyone please help me with the above method which writes to the XML the data the user has entered into the text box controls? I'm not sure how to load the previously created XML document (from my createAndLoadXML method), and how to write within the root element (software) using LINQ to XML.
Try this out. I think this should get you what you want assuming the XML exists beforehand since you are calling createAndLoadXML before this method. I wrote this in NotePad++, so I may have a error or two.
private void writeToXML()
{
// Method to write lines to XML file based on user input
// Sets string variables
string fileName = softwareNameTextBox.Text;
string filePath = filePathTextBox.Text;
string fileType = installerType.Text.ToString();
string installSwitches = installSwitchesTextBox.Text;
string FILE_PATH = "bla.xml";
XDocument xDoc = XDocument.Load(FILE_PATH);
xDoc.Root.Add(new XElement("software_entry",
new XAttribute("name", fileName),
new XAttribute("path", filePath),
new XAttribute("type", fileType),
new XAttribute("switches", installSwitches)
));
xDoc.Save(FILE_PATH);
}

Categories

Resources