Fastest way to add new node to end of an xml?
You need to use the XML inclusion technique.
Your error.xml (doesn't change, just a stub. Used by XML parsers to read):
<?xml version="1.0"?>
<!DOCTYPE logfile [
<!ENTITY logrows
SYSTEM "errorrows.txt">
]>
<Errors>
&logrows;
</Errors>
Your errorrows.txt file (changes, the xml parser doesn't understand it):
<Error>....</Error>
<Error>....</Error>
<Error>....</Error>
Then, to add an entry to errorrows.txt:
using (StreamWriter sw = File.AppendText("logerrors.txt"))
{
XmlTextWriter xtw = new XmlTextWriter(sw);
xtw.WriteStartElement("Error");
// ... write error messge here
xtw.Close();
}
Or you can even use .NET 3.5 XElement, and append the text to the StreamWriter
:
using (StreamWriter sw = File.AppendText("logerrors.txt"))
{
XElement element = new XElement("Error");
// ... write error messge here
sw.WriteLine(element.ToString());
}
See also Microsoft's article Efficient Techniques for Modifying Large XML Files
Append a New Node in already existing XML Document
Few things you should be aware of:
The Xml closing tag is missing
/
.Xml is case sensitive.
<HBeds>
and<Hbeds>
are different!
Here's an example how we can insert <HId>
nodes as asked in the question.
In my Project I have the xml file, "MyXml.xml" :
<?xml version="1.0" encoding="utf-8" ?>
<NewDataSet>
<Table>
<HotelName>A</HotelName>
<Rating>5*</Rating>
<Hzone>Central </Hzone>
<HBeds>B</HBeds>
<Address>Lodhi Road</Address>
<Soh>-</Soh>
<Recommended>0</Recommended>
<DetailStr>-</DetailStr>
<Block>N</Block>
</Table>
<Table>
<HotelName>B</HotelName>
<Rating>5*</Rating>
<Hzone>Central </Hzone>
<HBeds>A</HBeds>
<Address>Lodhi Road</Address>
<Soh>Bh</Soh>
<Recommended>0</Recommended>
<DetailStr>-</DetailStr>
<Block>N</Block>
</Table>
</NewDataSet>
I have a test webform WebForm1.aspx with this markup:
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="WebForm1.aspx.vb" Inherits="VBXmlTest.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="txtxmlfile" runat="server">Vancouver</asp:TextBox>
</div>
</form>
</body>
</html>
In the code behind, in Page_Load
I am calling ProcessXml
function, My WebForm1.aspx.vb is:
Imports System.Xml
Public Class WebForm1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
ProcessXml()
End Sub
Private Sub ProcessXml()
Dim xDoc As New XmlDocument
Dim filePath As String = Server.MapPath("~/MyXml.xml")
xDoc.Load(filePath)
Dim XmlNodeListPackes As XmlNodeList
XmlNodeListPackes = xDoc.SelectNodes("/NewDataSet/Table")
Dim Hid As Integer
For Each xNode As XmlNode In XmlNodeListPackes
Dim strHotelBeds As String = xNode.SelectSingleNode("HBeds").InnerText
Dim City As String = txtxmlfile.Text
Hid = DAL.GetHotelBedId(strHotelBeds, City)
Dim hidNode As XmlNode = xNode.SelectSingleNode("HId")
If hidNode IsNot Nothing Then
hidNode.InnerText = Hid
Else
hidNode = xDoc.CreateNode(XmlNodeType.Element, "HId", "")
hidNode.InnerText = Hid
xNode.AppendChild(hidNode)
End If
Next
xDoc.Save(filePath)
End Sub
End Class
And to test, I have replaced the DAL with a Module, just for testing:
Public Module DAL
Public Function GetHotelBedId(ByVal strHotelBeds As String, ByVal City As String) As Integer
Return 1
End Function
End Module
And this is the output xml, no matter how many times I run it:
<?xml version="1.0" encoding="utf-8"?>
<NewDataSet>
<Table>
<HotelName>A</HotelName>
<Rating>5*</Rating>
<Hzone>Central </Hzone>
<HBeds>B</HBeds>
<Address>Lodhi Road</Address>
<Soh>-</Soh>
<Recommended>0</Recommended>
<DetailStr>-</DetailStr>
<Block>N</Block>
<HId>1</HId>
</Table>
<Table>
<HotelName>B</HotelName>
<Rating>5*</Rating>
<Hzone>Central </Hzone>
<HBeds>A</HBeds>
<Address>Lodhi Road</Address>
<Soh>Bh</Soh>
<Recommended>0</Recommended>
<DetailStr>-</DetailStr>
<Block>N</Block>
<HId>1</HId>
</Table>
</NewDataSet>
How do I insert a new node to an existing XML
Looks like there's not such API in Android. However, You still have the following options to fix the issue:
- Look for some open-source library which provides such ability;
Do some manual string operations still using
XmlSerializer
, like provided below:private void testXMLFiles() {
//create a new file called "new.xml" in the SD card
final File newXmlFile = new File(Environment.getExternalStorageDirectory() + "/download/teste/audit.xml");
RandomAccessFile randomAccessFile = null;
final boolean fileExists = newXmlFile.exists();
String lastLine = null;
if (fileExists) {
try {
randomAccessFile = new RandomAccessFile(newXmlFile, "rw");
randomAccessFile.seek(0);
if (null != randomAccessFile) {
final Scanner scanner = new Scanner(newXmlFile);
int lastLineOffset = 0;
int lastLineLength = 0;
while (scanner.hasNextLine()) {
// +1 is for end line symbol
lastLine = scanner.nextLine();
lastLineLength = lastLine.length() + 2;
lastLineOffset += lastLineLength;
}
// don't need last </root> line offset
lastLineOffset -= lastLineLength;
// got to string before last
randomAccessFile.seek(lastLineOffset);
}
} catch(FileNotFoundException e) {
Log.e("FileNotFoundException", "can't create FileOutputStream");
} catch (IOException e) {
Log.e("IOException", "Failed to find last line");
}
} else {
try {
newXmlFile.createNewFile();
} catch(IOException e) {
Log.e("IOException", "exception in createNewFile() method");
}
try {
randomAccessFile = new RandomAccessFile(newXmlFile, "rw");
} catch(FileNotFoundException e) {
Log.e("FileNotFoundException", "can't create FileOutputStream");
}
}
//we create a XmlSerializer in order to write xml data
XmlSerializer serializer = Xml.newSerializer();
if (randomAccessFile == null) {
return;
}
try {
final StringWriter writer = new StringWriter();
serializer.setOutput(writer);
if (!fileExists) {
serializer.startDocument(null, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startTag(null, "root");
} else {
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
}
serializer.startTag(null, "child1");
serializer.endTag(null, "child1");
serializer.startTag(null, "child2");
serializer.attribute(null, "attribute", "value");
serializer.endTag(null, "child2");
serializer.startTag(null, "child3");
serializer.text("some text inside child3");
serializer.endTag(null, "child3");
if (!fileExists) {
serializer.endTag(null, "root");
}
serializer.flush();
if (lastLine != null) {
serializer.endDocument();
writer.append(lastLine);
}
// Add \n just for better output in console
randomAccessFile.writeBytes(writer.toString() + "\n");
randomAccessFile.close();
Toast.makeText(getApplicationContext(), "Save!", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Log.e("Exception","error occurred while creating xml file");
e.printStackTrace();
}
}
Its output after second run is the following (quite similar to what You expect):
<?xml version='1.0' standalone='yes' ?>
<root>
<child1 />
<child2 attribute="value" />
<child3>some text inside child3</child3>
<child1 />
<child2 attribute="value" />
<child3>some text inside child3</child3></root>
- Store all tags from initial xml (e.g. using SAXParser you can read tags, write to new file the same time and apppend new ones at the end using
XMLSerializer
);
Add new Node to the xml file
You need to ImportNode and AppendChild it then: xDocumentArchived.DocumentElement.AppendChild(xDocumentArchived.ImportNode(node, true);
. And at the end you need to call Save on xDocumentArchived
: xDocumentArchived.Save(archivedXmlFile);
.
How I can insert node at beginning xml file?
Why cant you use the firstChild method and then insert before? Like
n.insertBefore(a, n.getFirstChild());
Full code
public void insertNewProject(Project entity) {
String filePath = "location.xml";
File xmlFile = new File(filePath);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder;
try {
dBuilder = dbFactory.newDocumentBuilder();
Document doc;
doc = dBuilder.parse(xmlFile);
doc.getDocumentElement().normalize();
Node n = doc.getElementsByTagName("n").item(0);
Element a = doc.createElement("a");
n.insertBefore(a, n.getFirstChild());
Element b = doc.createElement("b");
b.appendChild(doc.createTextNode(entity.getLocation()));
a.appendChild(b);
Element c = doc.createElement("c");
c.appendChild(doc.createTextNode(entity.getName()));
a.appendChild(c);
doc.getDocumentElement().normalize();
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource domSource = new DOMSource(doc);
StreamResult streamResult = new StreamResult(new File("location.xml"));
transformer.transform(domSource, streamResult);
} catch (ParserConfigurationException pce) {
return;
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (TransformerException tfe) {
return;
}
}
How do I add and rearrange nodes of an XML file in R?
The "xml2" package has a simple syntax for adding and removing nodes from an XML document.
To rearrange the structure you first need to locate and copy the nodes you want to move, then remove them from the document and then add original list back into the document. I would not recommend this unless you have a very specific reason for doing so.
library(xml2)
library(magrittr)
page <- read_xml("<dataset>
<language>
<name>Old_Irish</name>
<definite_source>Demonstrative1</definite_source>
<n_cases>5</n_cases>
</language>
<language>
<name>Irish</name>
<definite_source>Demonstrative2</definite_source>
<n_cases>4</n_cases>
</language>
</dataset>")
#Find the nodes you want to relocate
nodesdefinite <- page %>% xml_find_all(".//definite_source")
html_structure(page)
#Remove the Nodes
page %>% xml_find_all(".//definite_source") %>% xml_remove()
#Add them where desired
page %>% xml_find_all(".//n_cases") %>% xml_add_sibling(nodesdefinite, .where="after")
#Verify the structure
html_structure(page)
page %>% xml_find_all(".//definite_source")
#To add a node
#Using the add_child, add the new node at the end of the list
page %>% xml_find_all(".//language") %>% xml_add_child("newNode", "new value")
html_structure(page) #Verify the structure
#Using the add_sibling, better control for placement
page %>% xml_find_all(".//n_cases") %>% xml_add_sibling("newSibling", pi, .where="before")
Easiest way to add xml a node with a bunch of children nodes in .Net?
If you can use .NET 4, I would recommend looking at XDocument
. Here is an example for adding elements to a document:
http://msdn.microsoft.com/en-us/library/system.xml.linq.xdocument.add.aspx
You can use XDocument.Parse
to initialize the document from a string, or XDocument.Load
to initialize from a file (there are other overloads too).
Then, you can navigate to the element where you want to insert, and do an XElement.Add
()
Here is some sample code that puts your XML element into another XDocument. I'm just adding the XML to the first "Elem" node of the target XDcoument, but you can tweak the code to add it multiple times, etc...
public static void Main()
{
var xelementToAdd = XElement.Parse(@"
<TablixRow>
<Height>0.23622in</Height>
<TablixCells>
<TablixCell>
<CellContents>
<Textbox Name='Textbox1'>
<CanGrow>true</CanGrow>
<KeepTogether>true</KeepTogether>
<Paragraphs>
<Paragraph>
<TextRuns>
<TextRun>
<Value/>
<Style/>
</TextRun>
</TextRuns>
<Style/>
</Paragraph>
</Paragraphs>
<DefaultName>Textbox1</DefaultName>
<Style>
<Border>
<Style>None</Style>
</Border>
<PaddingLeft>2pt</PaddingLeft>
<PaddingRight>2pt</PaddingRight>
<PaddingTop>2pt</PaddingTop>
<PaddingBottom>2pt</PaddingBottom>
</Style>
</Textbox>
</CellContents>
</TablixCell>
<TablixCell>
<CellContents>
<Textbox Name='Textbox5'>
<CanGrow>true</CanGrow>
<KeepTogether>true</KeepTogether>
<Paragraphs>
<Paragraph>
<TextRuns>
<TextRun>
<Value/>
<Style/>
</TextRun>
</TextRuns>
<Style/>
</Paragraph>
</Paragraphs>
<DefaultName>Textbox5</DefaultName>
<Style>
<Border>
<Style>None</Style>
</Border>
<PaddingLeft>2pt</PaddingLeft>
<PaddingRight>2pt</PaddingRight>
<PaddingTop>2pt</PaddingTop>
<PaddingBottom>2pt</PaddingBottom>
</Style>
</Textbox>
</CellContents>
</TablixCell>
</TablixCells>
</TablixRow>");
// you might use XDocument.Load() here instead of Parse()
var xdoc = XDocument.Parse(@"
<Report xmlns='http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition'
xmlns:rd='http://schemas.microsoft.com/SQLServer/reporting/reportdesigner'
xmlns:msxsl='urn:schemas-microsoft-com:xslt'
xmlns:xs='http://www.w3.org/2001/XMLSchema'
xmlns:msdata='urn:schemas-microsoft-com:xml-msdata'>
<rd:DrawGrid>true</rd:DrawGrid>
<ReportParameters></ReportParameters>
</Report>
");
XNamespace ns1 = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition";
XNamespace ns2 = "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner";
XNamespace ns3 = "urn:schemas-microsoft-com:xslt";
XNamespace ns4 = "http://www.w3.org/2001/XMLSchema";
XNamespace ns5 = "urn:schemas-microsoft-com:xml-msdata";
var e = xdoc.Root.Elements(ns1 + "ReportParameters")
.FirstOrDefault();
e.Add(xelementToAdd);
xdoc.Save(@"c:\temp\foo2.xml");
}
And for what it's worth, I tweaked your sample XML to remove the namespace prefix (namespaces are an issue separate from your question) and replaced the double quotes with single quotes (the XML is otherwise equivalent).
Updated: Yes, you are running into a namespace problem. Even though your <ReportParameters>
element does not have a prefix like <rd:DrawGrid>
, it's using the default namespace, and you must specify it. Take a look at the updated sample, which should do what you want. Hope this helps!
How to add new Node to xml file
I usually use Linq's XDocument to deal with XML. You would need to add a System.Xml.Linq to your using statements. It would be something like:
string movieListXML = @"c:\test\movies.xml";
XDocument doc = XDocument.Load(movieListXML);
foreach (XElement movie in doc.Root.Descendants("Movie"))
{
movie.Add(new XElement("Time", "theTime"));
}
doc.Save(movieListXML);
Related Topics
Dtd Prohibited in Xml Document Exception
Unlock Windows Programmatically
C# - Making All Derived Classes Call the Base Class Constructor
Cross-Thread Winforms Control Editing
Why Does This Simple .Net Console App Have So Many Threads
Why Use Generic Constraints in C#
Impersonate User in Windows Service
Is .Getawaiter().Getresult(); Safe for General Use
Controls in Container Form Come Over Child Form
Linq: Passing Lambda Expression as Parameter to Be Executed and Returned by Method
File Write Permission Issue Under "Program Files" Folder
What Happens While Waiting on a Task's Result