I need to creat an XML in this form:
<?xml version="1.0" encoding="UTF-8"?>
<CastleConfigTop xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xsd/c5c.xsd" Format="1">
<ProjectInfo ProjectCode="1" ProjectIdentifier="C5_Valeo_SL">
<ProjectName>TheProjectName</ProjectName>
</ProjectInfo>
<Options />
<ConfigFile Name="C5_Valeo_SL">
<History>
</History>
<Includes>
</Includes>
<Options>
</Options>
<DataTypes>
<Options>
<options />
</Options>
<ArgTypes />
<Enums />
<Lookups />
<Doc />
</DataTypes>
<Interfaces />
<Modules>
</Modules>
<ExexutionUnits />
<Doc></Doc>
</ConfigFile>
</CastleConfigTop>
And im using this code, where the object ccTop contains all the necessary classes:
public void saveXmlPath()
{
//xmldoc.Save(this.OutputPath+"\\"+projectName+".C5C");
XmlSerializer serializer = new XmlSerializer(typeof(CastleConfigTop));
string outpath = this.OutputPath + "\\" + projectName + ".C5C";
using (TextWriter writer = new StreamWriter(#outpath))
{
serializer.Serialize(writer, ccTop);
}
}
But the output XMl has the encoding style "utf-8" (lower case) and a different namespace like this:
<?xml version="1.0" encoding="utf-8"?>
<CastleConfigTop xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ProjectInfo ProjectCode="1" ProjectIdentifier="C5_Valeo_SL">
<ProjectName> ProjectName </ProjectName>
</ProjectInfo>
<Options />
<ConfigFile Name="C5_Valeo_SL">
<History>
</History>
<Includes>
</Includes>
<Options>
</Options>
<DataTypes>
<Options />
<ArgTypes />
<Enums />
<Lookups />
<Doc />
</DataTypes>
<Interfaces />
<Modules>
</Modules>
<Difs>
</Difs>
<ExexutionUnits />
<Doc>SAS Volvo SPA</Doc>
</ConfigFile>
</CastleConfigTop>
Any Idea about how to make them exactly similar?
You can post-process this using LINQ to XML to get what you want.
Create an XDocument and serialize your object to this:
var doc = new XDocument();
using (var writer = doc.CreateWriter())
{
serializer.Serialize(writer, ccTop);
}
Then modify the declaration and attributes:
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
doc.Root.Attributes()
.Where(a => a.IsNamespaceDeclaration && a.Value == "http://www.w3.org/2001/XMLSchema")
.Remove();
doc.Root.Add(new XAttribute(xsi + "noNamespaceSchemaLocation", "xsd/c5c.xsd"));
doc.Root.Add(new XAttribute("Format", 1));
And then write to disc. Note you can use XmlWriterSettings to set various options for writing, such as indentation.
var settings = new XmlWriterSettings
{
Indent = true
};
using (var writer = XmlWriter.Create(FILENAME, settings))
{
doc.WriteTo(writer);
}
Or if you can just use Save (which gives you less options, but the defaults should be fine):
doc.Save(FILENAME);
I wouldn't expect the declaration to be an issue in lower case, but if it is you'll have to modify this using some other means - XmlWriter takes an Encoding and will convert this internally to the lowercase form, so changing this in the XDocument won't help.
TextWriter writer = new StreamWriter(outpath , true, Encoding.ASCII);
You can have a try with these code
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
saveXmlPath();
}
const string FILENAME = #"c:\temp\test.xml";
public static void saveXmlPath()
{
CastleConfigTop ccTop = new CastleConfigTop();
XmlSerializer serializer = new XmlSerializer(typeof(CastleConfigTop));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("xsi","xsd/c5c.xsd");
ns.Add("", "http://www.w3.org/2001/XMLSchema-instance");
using (TextWriter writer = new StreamWriter(FILENAME))
{
serializer.Serialize(writer, ccTop, ns);
}
}
}
[XmlRoot(ElementName = "CastleConfigTop", Namespace = "xsi")]
public class CastleConfigTop
{
}
}
Related
I have an XML like this
<Root>
<Branch>
<Child Id="0">
<Reference Name="B0"/>
<Details Number="2">
<Detail Height="50"/>
<Detail Weight="3"/>
</Details>
</Child>
<Child Id="2">
<Reference Name="B2"/>
<Details Number="2">
<Detail Height="55"/>
<Detail Weight="3.5"/>
</Details>
</Child>
</Branch>
</Root>
I want to add a new block of data for Child ID=1 after Child ID=0 data block
It is probably easier to add the new child to the current list. Then sort the children. See the xml linq code below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XElement newChild = new XElement("Child", new object[] {
new XAttribute("Id", "1"),
new XElement("Reference", new XAttribute("Name", "B1")),
new XElement("Details", new object[] {
new XAttribute("Number", "2"),
new XElement("Detail", new XAttribute("Height","52")),
new XElement("Detail", new XAttribute("Weight","3.25"))
})
});
XDocument doc = XDocument.Load(FILENAME);
XElement branch = doc.Descendants("Branch").FirstOrDefault();
branch.Add(newChild);
List<XElement> orderedChildren = branch.Elements("Child").OrderBy(x => (int)x.Attribute("Id")).ToList();
XElement newBranch = new XElement("Branch", orderedChildren);
branch.ReplaceWith(newBranch);
}
}
}
I am a new user on this forum and I'm not a highly experienced developer/programmer. Before asking this question, I searched and looked through Stack Overflow and some Microsoft suggested links, but I didn't find what I was looking for.
I've got the following XML file:
<?xml version="1.0" standalone="no" ?>
<WndPos name="FrontEnd.Login" l="703" r="1264" t="323" b="909" />
<LayerManager />
<ViewLayers name="RoofLayout" roof="1" nlwalls="1">
<Layer level="-1" module="1" name="Walls" locked="0" visible="1" />
</ViewLayers>
<DirProfiles>
<ProfileInfo ProfileName="ControlCQFT" JobPath="C:\Jobs" DatabasePath="D:\Database\ControlCQFT" />
</DirProfiles>
<DirHistory>
<ProfileInfo Use="Job" Path="C:\Jobs" />
</DirHistory>
I need to replace the entire <DirProfiles> node. The incoming node can be empty, which looks like <DirProfiles />. The new node that I want to insert is in the format:
<DirProfiles>
<ProfileInfo ProfileName="Control1" JobPath="D:\Client1\JobsA" DatabasePath="D:\Database\Control1" />
. . . . .
</DirProfiles>
I tried to handle the problem as a simple string replacement, but I didn't get the result that I needed.
Edit:
My apology, I didn't realized that my xml file is fragment xml document and not full XML as per spec.
Given your input file is a malformed XML file that doesn't contain a root node, you can get around this with a bit of string manipulation.
Here's the file you say you have:
<?xml version="1.0" standalone="no" ?>
<WndPos name="FrontEnd.Login" l="703" r="1264" t="323" b="909" />
<LayerManager />
<ViewLayers name="RoofLayout" roof="1" nlwalls="1">
<Layer level="-1" module="1" name="Walls" locked="0" visible="1" />
</ViewLayers>
<DirProfiles>
<ProfileInfo ProfileName="ControlCQFT" JobPath="C:\Jobs" DatabasePath="D:\Database\ControlCQFT" />
</DirProfiles>
<DirHistory>
<ProfileInfo Use="Job" Path="C:\Jobs" />
</DirHistory>
Here's how to work with it:
var sourceFileName = #"C:\{path}\xml_fragments.txt";
var text = $"<root>{String.Join(Environment.NewLine, File.ReadLines(sourceFileName).Skip(1))}</root>";
var doc = XDocument.Parse(text);
doc.Root.Element("DirProfiles").Elements().Remove();
doc.Root.Element("DirProfiles").Add(
new XElement(
"ProfileInfo",
new XAttribute("ProfileName", "Control1"),
new XAttribute("JobPath", #"D:\Client1\JobsA"),
new XAttribute("DatabasePath", #"D:\Database\Control1")));
That gives me:
<root>
<WndPos name="FrontEnd.Login" l="703" r="1264" t="323" b="909" />
<LayerManager />
<ViewLayers name="RoofLayout" roof="1" nlwalls="1">
<Layer level="-1" module="1" name="Walls" locked="0" visible="1" />
</ViewLayers>
<DirProfiles>
<ProfileInfo ProfileName="Control1" JobPath="D:\Client1\JobsA" DatabasePath="D:\Database\Control1" />
</DirProfiles>
<DirHistory>
<ProfileInfo Use="Job" Path="C:\Jobs" />
</DirHistory>
</root>
See following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
string xml = File.ReadAllText(FILENAME);
XElement doc = new XElement("Root");
doc.Add(XElement.Parse(xml));
XElement dirProfiles = doc.Descendants("DirProfiles").FirstOrDefault();
XElement profileInfo = dirProfiles.Element("ProfileInfo");
profileInfo.SetAttributeValue("ProfileName", "Control1");
profileInfo.SetAttributeValue("JobPath", #"D:\Client1\JobsA");
profileInfo.SetAttributeValue("DatabasePath", #"D:\Database\Control1");
}
}
}
You can parse the XML data to a C# class model, and after that could do the data changes as per requirement. After changes, you can again parse the model object to XML and rewrite the XML string on the same file.
Refer this link for generate a class structure by available XML: https://www.c-sharpcorner.com/blogs/convert-xml-json-file-to-c-sharp-class
And Use this code to Convert Xml to a C# class object
public static T ConvertXmlToObject<T>(String xml)
{
T result = default(T);
try
{
using (TextReader reader = new StringReader(xml))
{
try
{
result =
(T)new XmlSerializer(typeof(T)).Deserialize(reader);
}
catch (InvalidOperationException)
{
// Throw message for invalid XML
}
}
}
catch (Exception ex)
{
}
return result;
}
Call the function like :
var entity = ConvertXmlToObject<ModelClass>(XMLString);
User this code to convert again Object to XML
public static string ConvertObjectToXML<T>(T ModelClass)
{
XmlSerializer xsObject = new XmlSerializer(typeof(T));
var inputObject = ModelClass;
var xmlString = "";
using (var sw = new StringWriter())
{
using (XmlWriter writer = XmlWriter.Create(sw))
{
xsObject.Serialize(writer, inputObject);
xmlString = sw.ToString();
}
}
return xmlString;
}
Call this function like :
string xmlString = ConvertObjectToXML<ModelClass>(ModelClassObject);
I want add a namespace in my xml root. Below is the result I want:
<ReconciliationRequest xmlns="http://schemas.xxx.co.xxx/test/crm">
<Patient>
<NHSNumber>1234567890</NHSNumber>
<PDSChangeSerialNumber>1234</PDSChangeSerialNumber>
</Patient>
<!-- ... -->
</ReconciliationRequest>
But I'm getting below result
<ReconciliationRequest>
<Patient>
<NHSNumber>1234567890</NHSNumber>
<PDSChangeSerialNumber>1234</PDSChangeSerialNumber>
</Patient>
<!-- ... -->
</ReconciliationRequest>
Below is the code I'm using to add the namespace:
TextWriter writer = new StreamWriter("D:\\ReconcillationRequest.xml");
XmlSerializerNamespaces nameSpace = new XmlSerializerNamespaces();
nameSpace.Add(string.Empty, "http://schemas.XXXX.co.XX/Test/crm");
serializer.Serialize(writer, obj, nameSpace);
writer.Close();
I'm unable to add the namespace. Please guide me on this.
In my case I want to add multiple root nodes to the given xml schema. So I have to append the different user elements with it's child nodes in multiple times by appending with the previous contents in the xml file. My problem is how can I add multiple root elements? (I could add one root element but no idea how to add next ).
This is the xml schema
<?xml version="1.0" encoding="utf-8"?>
<SessionId>
<Scource>
<User username="AB">
<DOB>25/5/1980</DOB>
<FirstName>AVS</FirstName>
<LastName>WDW</LastName>
<Location>FWAWE</Location>
</User>
<User username="AqB">
<DOB>25/5/1980</DOB>
<FirstName>AVS</FirstName>
<LastName>WDW</LastName>
<Location>FWAWE</Location>
</User>
</Scource>
</SessionId>
This is my C# code
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
namespace FilteringNightwing
{
class Test
{
static void Main(string[] args) {
string fileLocation = "clients.xml";
if (!File.Exists(fileLocation))
{
XmlTextWriter writer = new XmlTextWriter(fileLocation, null);
writer.WriteStartElement("SessionId");
writer.WriteEndElement();
writer.Close();
}
// Load existing clients and add new
XElement xml = XElement.Load(fileLocation);
xml.Add(new XElement("User",
new XAttribute("username", "AqB"),
new XElement("DOB", "25/5/1980"),
new XElement("FirstName", "AVS"),
new XElement("LastName", "WDW"),
new XElement("Location", "FWAWE")));
xml.Save(fileLocation);
}
}
}
How can I add "Source" tag as another root element. All your answers are welcome.
You can't have more than one root node. Parsing the following will give you an error.
XElement root = XElement.Parse("<a></a><b></b>");
This will error too:
XElement root = XElement.Parse("<a></a><a></a>");
If you want multiple children nodes to the root node, that is perfectly fine. You can have nodes with the same name or different. Such as:
<a>
<b />
<c>
<d />
</c>
<b />
</a>
Add new user to Scource:
XElement xml = XElement.Load(fileLocation);
XElement scource = xml.Element("Scource"); // Find Scource here
scource.Add(new XElement("User", // Add new user to Scource here
new XAttribute("username", "AqB"),
new XElement("DOB", "25/5/1980"),
new XElement("FirstName", "AVS"),
new XElement("LastName", "WDW"),
new XElement("Location", "FWAWE")));
xml.Save(fileLocation);
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><SessionId><Source></Source></SessionId>";
XDocument doc = XDocument.Parse(xml);
XElement source = doc.Descendants("Source").FirstOrDefault();
source.Add(new XElement("User", new object[] {
new XAttribute("username", "AqB"),
new XElement("DOB", "25/5/1980"),
new XElement("FirstName", "AVS"),
new XElement("LastName", "WDW"),
new XElement("Location", "FWAWE")
}));
}
}
}
When using the default settings with the XmlSerializer it will output the XML as a formated value.
IE: something along these lines.
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfStock xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Stock>
<ProductCode>12345</ProductCode>
<ProductPrice>10.32</ProductPrice>
</Stock>
<Stock>
<ProductCode>45632</ProductCode>
<ProductPrice>5.43</ProductPrice>
</Stock>
</ArrayOfStock>
How does one prevent any type of formatting on the output? So what I am looking to achieve is this.
<?xml version="1.0" encoding="utf-8"?><ArrayOfStock xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><Stock><ProductCode>123456</ProductCode><ProductPrice>10.57</ProductPrice></Stock><Stock><ProductCode>789123</ProductCode><ProductPrice>133.22</ProductPrice></Stock></ArrayOfStock>
EDIT: The full code of my method is
public static String Serialize(Stock stock)
{
XmlSerializer serializer = new XmlSerializer(typeof(Stock));
using (StringWriter stringWriter = new StringWriter())
{
serializer.Serialize(stringWriter, stock);
return stringWriter.ToString();
}
}
Not very intuitive, but the Indent property on the XmlWriterSettings controls the whole formatting:
var serializer = new XmlSerializer(typeof(MyClass));
using (var writer = new StreamWriter("file.path"))
using (var xmlWriter = XmlWriter.Create(writer, new XmlWriterSettings { Indent = false }))
{
serializer.Serialize(xmlWriter, myObject);
}
There are a few more options on XmlWriterSettings that you might want to explore.
It is simple to parse the resulting XML and remove and newlines and tabs...
using 'Indent = false', will still put elements on newlines no?
..
XmlSerializer xmlser = new XmlSerializer(...);
XmlWriterSettings settings = new XmlWriterSettings {Indent = false};
using (XmlWriter xw = XmlWriter.Create(stream, settings))
{
...