add new lines when generating xml from object - c#

this is the code
XmlDocument xml = new XmlDocument();
XmlElement root = xml.CreateElement("customers");
xml.AppendChild(root);
foreach (var cust in customerlist)
{
XmlElement child = xml.CreateElement("customer");
child.SetAttribute("CustomerId", cust.CustomerId.ToString());
child.SetAttribute("CustomerName", cust.CustomerName);
child.SetAttribute("PhoneNumber", cust.PhoneNumber);
child.SetAttribute("Email", cust.Email);
root.AppendChild(child);
}
string s = xml.OuterXml;
I want my string to have next lines added to it instead of a single xml document
My string is coming as continuous
< x >xxxxx< /x > < x >xxxxx< /x >

You can use the XmlTextWriter class to format the XML as a string like this:
StringWriter string_writer = new StringWriter();
XmlTextWriter xml_text_writer = new XmlTextWriter(string_writer);
xml_text_writer.Formatting = Formatting.Indented;
xml.WriteTo(xml_text_writer); // xml is your XmlDocument
string formattedXml = string_writer.ToString();

Related

Can't get attribute value with C# XPath

I've spent so much time with this already, still can't get the value of NTE attribute. Can someone please help?
C#
StreamReader sr = new StreamReader(resp.GetResponseStream());
XPathDocument xmlDoc = new XPathDocument(sr); // holds xml document
XPathNavigator xmlNav = xmlDoc.CreateNavigator(); //evaluates XPath expressions
XPathNodeIterator node = xmlNav.Select("/DATA2SC/CALL");
string dne = xmlNav.GetAttribute("NTE", "");
Console.WriteLine(dne);
sr.Close();
XML
<?xml version="1.0"?>
<DATA2SC PIN="00000">
<CALL
TR_NUM="00000001"
STATUS="WAITING_FOR_APPROVAL"
NTE="$15.00">
<PROBLEM>
Text
</PROBLEM>
</CALL>
</DATA2SC>
Can you try this code please ?
I already check and it's work
StreamReader sr = new StreamReader("c:\\x.xml");
XPathDocument xmlDoc = new XPathDocument(sr); // holds xml document
XPathNavigator xmlNav = xmlDoc.CreateNavigator(); //evaluates XPath expressions
var node = xmlNav.SelectSingleNode("/DATA2SC/CALL");
string dne = node.GetAttribute("NTE", "");
Console.WriteLine(dne);
OR
XDocument docXmlWorld = XDocument.Load("c:\\x.xml");
foreach (var node1 in docXmlWorld.Descendants("DATA2SC"))
{
foreach (var node2 in node1.Descendants("CALL"))
{
string dne = node2.Attribute("NTE").Value;
Console.Out.WriteLine(dne);
}
}
Or you can do like this too:
XDocument docXmlWorld = XDocument.Load("c:\\x.xml");
//Get the first child => [DATA2SC]
XElement elementNodeDATA2SC = docXmlWorld.Element("DATA2SC");
//Get the first child => [CALL]
XElement elementNodeCALL = elementNodeDATA2SC.Element("CALL");
//Get the attribute NTE from [CALL] node
string dne = elementNodeCALL.Attribute("NTE").Value;
Console.Out.WriteLine(dne);
The Select method, returns a collection of all nodes with the specified XPath.
You can use SelectSingleNode, to select the first node.
var node = xmlNav.SelectSingleNode("/DATA2SC/CALL");
string dne = node.GetAttribute("NTE", "");

Incorrect parsing of Textbox in docx by OpenXML

I am reading a .docx file using OpenXML in C#. It reads everything correctly but strangely, the content of textbox is being read thrice. What could be wrong? Here is the code to read .docx:
public static string TextFromWord(String file)
{
const string wordmlNamespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
StringBuilder textBuilder = new StringBuilder();
using (WordprocessingDocument wdDoc = WordprocessingDocument.Open(file, false))
{
// Manage namespaces to perform XPath queries.
NameTable nt = new NameTable();
XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("w", wordmlNamespace);
// Get the document part from the package.
// Load the XML in the document part into an XmlDocument instance.
XmlDocument xdoc = new XmlDocument(nt);
xdoc.Load(wdDoc.MainDocumentPart.GetStream());
XmlNodeList paragraphNodes = xdoc.SelectNodes("//w:p", nsManager);
foreach (XmlNode paragraphNode in paragraphNodes)
{
XmlNodeList textNodes = paragraphNode.SelectNodes(".//w:t", nsManager);
foreach (System.Xml.XmlNode textNode in textNodes)
{
textBuilder.Append(textNode.InnerText);
}
textBuilder.Append(Environment.NewLine);
}
}
return textBuilder.ToString();
}
The part of file I am talking about is:
The result is: I read it in a test application like this:
What's wrong here?

Inserting data at specific position in XML

I want to read an XML file and match tag </contrib-group> and write a string after this tag
string Final = File.ReadAllText(Npath);
string Oxml = path + "\\" + Oword + ".abs.xml";
if (File.Exists(Oxml))
{
StreamReader xml = new StreamReader(Oxml,Encoding.UTF8);
string xmltag = xml.ReadToEnd();
//File.OpenWrite(Oxml);
xml.Close();
StreamWriter write = new StreamWriter(Oxml, true, Encoding.UTF8);
Match tag = Regex.Match(xmltag, #"</contrib-group>");
if (tag.Success == true)
{
write.WriteLine(Environment.NewLine);
write.Write(Final);
}
}
So I need to write the string Final to the XML file called Oxml after the matched XML tag </contrib-group>
If you are willing to save the new content as a valid XML file which you can work with, you should use the XML classes for that approach, this should look like this (untested):
XmlDocument doc = new XmlDocument();
doc.Load("YourFile.xml");
XmlElement root = doc.DocumentElement;
XmlNodeList elemList = root.GetElementsByTagName("contrib-group");
for (int i=0; i < elemList.Count; i++)
{
XmlNode xnode = elemList[i];
XmlNode xnodeParent = xnode.ParentNode;
XMLNode newNode = doc.CreateNode(XmlNodeType.Element, "NodeName", "");
newNode.InnerText = "ContentInsideTheNode";
xnodeParent.InsertAfter(newNode, xnode);
}
doc.Save("YourFile.xml");
If you only need to replace the string for other purposes than saving it where having a valid XML is not an issue you can just handle it as a string and use the String.Replace (String, String) Method
string searchedTag = #"</contrib-group>";
string tagAndNewContent = #"</contrib-group>" + newContent;
string fileContentString = File.ReadAllText("YourFile.xml");
string ouput = fileContentString.Replace(searchedTag, tagAndNewContent);

Create kml file using xml elements

I want to create a kml file in c#. Now I have two problems:
What is the synatx to add the kml element in the xml file in order to have the line below in my kml file?
<kml xmlns="http://www.opengis.net/kml/2.2">
I have an array of points that i would like to form a linestring. How am I suppose to fill the coordinates element in xml for the kml file?.The following is my code so far.
CODE:
public void MakeKmlFile(string line)
{
CoordinateCollection coordinates = new CoordinateCollection();
char[] delimiterLine = { '|' };
char[] delimiterPoint = { ',' };
string[] route = line.Split(delimiterLine);
foreach (string point in route)
{
string[] route_point = line.Split(delimiterPoint);
double lat = double.Parse(route_point[1]);
double lon = double.Parse(route_point[0]);
coordinates.Add(new Vector(lat, lon));
}
XmlTextWriter writer = new XmlTextWriter("route.xml", System.Text.Encoding.UTF8);
writer.Formatting = Formatting.Indented;
writer.WriteStartElement("Document");
writer.WriteStartElement("Folder");
writer.WriteStartElement("name");
writer.WriteString("route");
writer.WriteEndElement();
writer.WriteStartElement("Placemark");
writer.WriteStartElement("Style");
writer.WriteStartElement("LineStyle");
writer.WriteStartElement("color");
writer.WriteString("ff0000ff");
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteStartElement("PolyStyle");
writer.WriteStartElement("fill");
writer.WriteString("2");
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteStartElement("LineString");
writer.WriteStartElement("coordinates");
This is the result i got:
<?xml version="1.0" encoding="utf-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<Name>Points.kml</Name>
<Placemark />
<Placemark />
<Placemark />
<Placemark />
<Placemark />
</Document>
You can create the KML document just like a normal XML document
XmlDocument xDoc = new XmlDocument();
XmlDeclaration xDec = xDoc.CreateXmlDeclaration("1.0", "utf-8", null);
XmlElement rootNode = xDoc.CreateElement("kml");
rootNode.SetAttribute("xmlns", #"http://www.opengis.net/kml/2.2");
xDoc.InsertBefore(xDec, xDoc.DocumentElement);
xDoc.AppendChild(rootNode);
XmlElement docNode = xDoc.CreateElement("Document");
rootNode.AppendChild(docNode);
XmlElement nameNodeMain = xDoc.CreateElement("Name");
XmlText nameTextMain = xDoc.CreateTextNode("Points.kml");
docNode.AppendChild(nameNodeMain);
nameNodeMain.AppendChild(nameTextMain);
That sets up the basic structure for your document then all you need to do is add each placemark (This is best done through a loop)
char[] delimiterLine = { '|' };
char[] delimiterPoint = { ',' };
string[] places = line.Split(delimiterLine);
for (int i = 0; i < places.length; i++)
{
string[] placeMark = places[i].split(delimiterPoint);
XmlElement placeNode = xDoc.CreateElement("Placemark");
docNode.AppendChild(placeNode);
XmlElement nameNode = xDoc.CreateElement("Name");
XmlText nameText = xDoc.CreateTextNode(placeMark[0]);
placeNode.AppendChild(nameNode);
nameNode.AppendChild(nameText);
XmlElement descNode = xDoc.CreateElement("Description");
XmlText descText = xDoc.CreateTextNode(placeMark[1]);
placeNode.AppendChild(descNode);
descNode.AppendChild(descText);
XmlElement pointNode = xDoc.CreateElement("Point");
placeNode.AppendChild(pointNode);
XmlElement coordNode = xDoc.CreateElement("coordinates");
XmlText coordText = xDoc.CreateTextNode(string.Format("{0},{1}", placeMark[2], placeMark[3]));
pointNode.AppendChild(coordNode);
coordNode.AppendChild(coordText);
}
return xDoc;
I haven't worked with LineStrings in KML before but I suspect the code to do that would be along the lines of the following:
XmlDocument xDoc = new XmlDocument();
XmlDeclaration xDec = xDoc.CreateXmlDeclaration("1.0", "utf-8", null);
XmlElement rootNode = xDoc.CreateElement("kml");
rootNode.SetAttribute("xmlns", #"http://www.opengis.net/kml/2.2");
xDoc.InsertBefore(xDec, xDoc.DocumentElement);
xDoc.AppendChild(rootNode);
XmlElement docNode = xDoc.CreateElement("Document");
rootNode.AppendChild(docNode);
XmlElement nameNodeMain = xDoc.CreateElement("Name");
XmlText nameTextMain = xDoc.CreateTextNode("Points.kml");
docNode.AppendChild(nameNodeMain);
nameNodeMain.AppendChild(nameTextMain);
XmlElement placeNode = xDoc.CreateElement("Placemark");
docNode.AppendChild(placeNode);
XmlElement nameNode = xDoc.CreateElement("Name");
XmlText nameText = xDoc.CreateTextNode("Test line");
placeNode.AppendChild(nameNode);
nameNode.AppendChild(nameText);
XmlElement lineStringNode = xDoc.CreateElement("LineString");
placeNode.AppendChild(lineStringNode);
XmlElement coordNode = xDoc.CreateElement("coordinates");
char[] delimiterLine = { '|' };
char[] delimiterPoint = { ',' };
string[] places = line.Split(delimiterLine);
for (int i = 0; i < places.length; i++)
{
string[] placeMark = places[i].split(delimiterPoint);
XmlText coordText = xDoc.CreateTextNode(string.Format("{0},{1}", placeMark[0], placeMark[1]));
pointNode.AppendChild(coordNode);
}
coordNode.AppendChild(coordText);
xDoc.Save("./KML/");
It basically involves moving my previous code around and creating a single XmlElement for each of the main elements required in a KML file and then iterating through the coordinates after splitting them in the line string.
Most direct solution is to tokenize the route (line string) and append coordinates in a string buffer then output as a value. No need to create the CoordinateCollection and separate Vector objects.
NOTE: In order to be valid KML you must output the longitude value first then latitude separated by comma (,) with no whitespace between the lon-lat values and whitespace must separate each lon-lat pair optionally with an altitude value.
Here's C# solution using the System.Xml.XmlTextWriter class:
XmlTextWriter writer = new XmlTextWriter(...);
writer.WriteStartElement("kml", "http://www.opengis.net/kml/2.2");
...
writer.WriteStartElement("LineString");
StringBuilder sb = new StringBuilder();
foreach (string point in route)
{
string[] route_point = point.Split(delimiterPoint);
if (route_point.Length >= 2)
{
double lon = double.Parse(route_point[0]);
double lat = double.Parse(route_point[1]);
sb.Append(' ').Append(lon).Append(',').Append(lat);
// coordinates.Add(new Vector(lat, lon));
}
}
writer.WriteStartElement("coordinates");
writer.WriteValue(sb.ToString());
writer.WriteEndElement(); // end coordinates
writer.WriteEndElement(); // end LineString
writer.WriteEndElement(); // end Placemark
...
writer.Close();

Building xml from scratch and getting result in string?

I'm trying to build up xml document from scratch with use linq-to-xml.
XElement root = new XElement("RootNode");
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", ""), root
);
for (int j = 0; j < 10; j++)
{
XElement element = new XElement("SetGrid");
element.SetElementValue("ID", j);
root.Add(element);
}
var reader = doc.CreateReader();//doc has 10 elements inside root element
string result = reader.ReadInnerXml();//always empty string
How can I get string from XDocument?
Just use string result = doc.ToString() or
var wr = new StringWriter();
doc.Save(wr);
string result = wr.ToString();
One option for empty string as per documentation.
XmlReader return:
All the XML content, including markup, in the current node. If the
current node has no children, an empty string is returned. If the
current node is neither an element nor attribute, an empty string is
returned.
try:
XmlReader reader = doc.CreateReader();
reader.Read();
string result = reader.ReadInnerXml()
var wr = new StringWriter();
doc.Save(wr);
var xmlString = wr.GetStringBuilder().ToString());
There's a full answer is here.
Long story short, you're missing reader.MoveToContent();
i.e. it should be:
var reader = root.CreateReader();
reader.MoveToContent(); // <- the missing line
string result = reader.ReadInnerXml();
This way the result won't be empty and you even don't have to create XDocument
So the full code from the original question + the fix is:
XElement root = new XElement("RootNode");
for (int j = 0; j < 10; j++)
{
XElement element = new XElement("SetGrid");
element.SetElementValue("ID", j);
root.Add(element);
}
var reader = root.CreateReader();// root has 10 elements
reader.MoveToContent(); // <-- missing line
string result = reader.ReadOuterXml(); // now it returns non-empty string
Output:
<RootNode><SetGrid><ID>0</ID></SetGrid><SetGrid><ID>1</ID></SetGrid><SetGrid><ID>2</ID></SetGrid><SetGrid><ID>3</ID></SetGrid><SetGrid><ID>4</ID></SetGrid><SetGrid><ID>5</ID></SetGrid><SetGrid><ID>6</ID></SetGrid><SetGrid><ID>7</ID></SetGrid><SetGrid><ID>8</ID></SetGrid><SetGrid><ID>9</ID></SetGrid></RootNode>
Note: The code is tested in Visual Studio 2013 / .NET Framework 4.5
MDSN Reference: XmlReader.ReadOuterXml

Categories