Transforming two xml files with XslCompiledTransform - c#

I have two xml files that I want to transform using XslCompiledTransform. Trouble is i have to do that in one transformation. I'm using .Transform method for the first file, while the other file is being referred to within xsl script. What I need as a result is html output that contains some data from both xml files. My code is:
XsltSettings settings = new XsltSettings(true, true);
XslCompiledTransform myXslTransform = new XslCompiledTransform();
myXslTransform.Load(openFileDialog1.FileName, settings, new XmlUrlResolver());
string HTMLoutput;
StringWriter writer = new StringWriter();
myXslTransform.Transform("file1.xml", null, writer);
HTMLoutput = writer.ToString();
writer.Close();
I catch following exception: "An error occurred while loading document'file2.xml" and InnerException: "For security reasons DTD is prohibited in this XML document. To enable DTD processing set the DtdProcessing property on XmlReaderSettings to Parse and pass the settings into XmlReader.Create method."
So how do I do what InnerExcetion tells me to do when XmlReader is being used by .Transform method? Or is there any other way to achieve this kind of transformation?

Use an XmlReader for file1.xml with XmlReaderSettings allowing Dtds, I think any secondary XML documents loaded with the document function are then loaded with the same settings.

Related

Save XML file at custom location

I'm a very beginner with c#.
I write a little XML converter. In the debug mode saves my xml files under bin/debug.
I use:
XmlWriter xw = XmlWriter.Create("Filename.xml")
When I compile the code and run it, the xml are not saved.
What can I do to ensure that the xml is stored at a particular path?
The save Location path comes from a form as a string
You just need to combine the path and the xml file name, then use XmlWriter to write xml element:
string pathName = Path.Combine(location, "Filename.xml"); // location is the string from your form.
using (var xw = XmlWriter.Create(pathName))
{
xw.WriteStartElement("myxml");
}
XmlWriter creates a new XmlWriter instance using the filename and XmlWriterSettings object. (Not saving the file!)
When you have the xml you can save it using System.IO:
File.WriteAllText(saveLocationPath, yourXML);

How to write xml file using C#

I am newer person in c# asp.net .
I want to write xml file in c# code behind file in my asp.net web application and pass this xml file as a string to a webservice . Can any one able to help me its will very useful for my project .
Thank you
As "fiver" had mentioned you could use the XmlDocument or the new simplified version XDocument for creating XML Documents. Here's a sample code snippet from MSDN for creating XML documents and writing to a file.
XDocument doc = new XDocument(
new XElement("Root",
new XElement("Child", "content")
)
);
doc.Save("Root.xml");
This will write the following text to the xml file
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Child>content</Child>
</Root>
Note: XDocument is supported only on .NET framework 3.5 and above
You can serialize objects in Xml by using XmlSerializer class:
Serializing to a file:
void SaveAsXmlToFile(object o, string fname)
{
XmlSerializer ser = new XmlSerializer(o.GetType());
using (var f = File.Open(fname, FileMode.OpenOrCreate))
ser.Serialize(f, o);
}
You can also use DataContractSerializer class the same way as XmlSerializer.
You can also serialize an object to a string, and return it:
Serializing to a string:
string ToXml(object o)
{
XmlSerializer ser = new XmlSerializer(o.GetType());
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
ser.Serialize(sw, o);
return sb.ToString();
}
Also, if you need more control over produced Xml, you can use structured xml objects, like XmlDocument and so on, or xml writing classes like XmlWriter as denoted in other answers.
You can use the XMLDocument class. It has various CreateXXX methods for creating XML elements.
It seem you don't need to save the XML file, so you can use the Save(String) method to serialize it to a string, when you are done.
See this question:
How can I build XML in C#?
If you're using .Net4 the XDocument class would work, for .Net2 use the XmlDocument.
The XDocument.ToString() directly returns the XML as a string. For the XmlDocument class you would use the XmlDocument.Save() method, to save to a stream or a TextWriter XmlDocument.OuterXml property.
Both examples on that question demonstrate how to output it as a string. You can use that to pass the string to your web service.
using System.Xml;
using System.Xml.Schema;
XmlTextWriter xtwFeed = new XmlTextWriter(Server.MapPath("rss.xml"), Encoding.UTF8);
xtwFeed.WriteStartDocument();
// The mandatory rss tag
xtwFeed.WriteStartElement("rss");
xtwFeed.WriteAttributeString("version", "2.0");
// Write all the tags like above and end all elements
xtwFeed.WriteEndElement();
xtwFeed.WriteEndDocument();
xtwFeed.Flush();
xtwFeed.Close();

LINQ to XML - Adding a node to a .csproj file

I've written a code generator, that generates C# files. If the file being generated is new, I need to add a reference to it to our .csproj file. I have the following method that adds a node to a .csproj file.
private static void AddToProjectFile(string projectFileName, string projectFileEntry)
{
StreamReader streamReader = new StreamReader(projectFileName);
XmlTextReader xmlReader = new XmlTextReader(streamReader);
XElement element;
XNamespace nameSpace;
// Load the xml document
XDocument xmlDoc = XDocument.Load(xmlReader);
// Get the xml namespace
nameSpace = xmlDoc.Root.Name.Namespace;
// Close the reader so we can save the file back.
streamReader.Close();
// Create the new element we want to add.
element = new XElement(nameSpace + "Compile", new XAttribute("Include", projectFileEntry));
// Add the new element.
xmlDoc.Root.Elements(nameSpace + "ItemGroup").ElementAt(1).Add(element);
xmlDoc.Save(projectFileName);
}
This method works fine. However, it doesn't add the node on a new line. It will append it to the previous line in the .csproj file. This makes for a bit of a mess when doing TFS merging. How can I add the new node on a new line?
Why are you using StreamReader and then XmlTextReader? Just pass the filename to the XDocument.Load. Then everything works as you would expect.
If you create the reader on your own XDocument can't modify its settings and thus the reader will report whitespaces which are then stored in the XLinq tree and when written out they disable automatic formatting in the writer. So you can either set IgnoreWhitespaces to true on your reader, or pass the input just as a filename, which will let XDocument use its own settings which will include IgnoreWhitespaces.
As a side note, please don't use XmlTextReader, a more spec compliant XML reader is created when you call XmlReader.Create.

Avoid XmlDocument validating namespaces in C#

I'm trying to find a way of indenting a HTML file, I've been using XMLDocument and just using a XmlTextWriter.
However I am unable to format it correctly for HTML documents because it checks the doctype and tries to download it.
Is there a "dumb" indenting mechanism that doesnt validate or check the document and does a best effort indentation? The files are 4-10Mb in size and they are autogenerated, we have to handle it internal - its fine, the user can wait, I just want to avoid forking to a new process etc.
Here's my code for reference
using (MemoryStream ms = new MemoryStream())
using (XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.Unicode))
{
XmlDocument doc = new XmlDocument();
// LoadSettings the unformatted XML text string into an instance
// of the XML Document Object Model (DOM)
doc.LoadXml(content);
// Set the formatting property of the XML Text Writer to indented
// the text writer is where the indenting will be performed
xtw.Formatting = Formatting.Indented;
// write dom xml to the xmltextwriter
doc.WriteContentTo(xtw);
// Flush the contents of the text writer
// to the memory stream, which is simply a memory file
xtw.Flush();
// set to start of the memory stream (file)
ms.Seek(0, SeekOrigin.Begin);
// create a reader to read the contents of
// the memory stream (file)
using (StreamReader sr = new StreamReader(ms))
return sr.ReadToEnd();
}
Essentially, right now I use a MemoryStream, XmlTextWriter and XmlDocument, once indented I read it back from the MemoryStream and return it as a string. Failures happen for XHTML documents and some HTML 4 documents because its trying to grab the dtds. I tried setting XmlResolver as null but to no avail :(
Without access to the specific X[H]TML causing the problems, it's hard to know if this will work, but have you tried using XDocument instead?
XDocument xdoc = XDocument.Parse(xml);
string formatted = xdoc.ToString();

What's the most streamlined way of performing a XSLT transformation in ASP.NET?

In other words, is there a faster, more concise way of writing the following code:
//Create an object for performing XSTL transformations
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(HttpContext.Current.Server.MapPath("/xslt/" + xsltfile.Value), new XsltSettings(true, false), new XmlUrlResolver());
//Create a XmlReader object to read the XML we want to format
//XmlReader needs an input stream (StringReader)
StringReader sr = new StringReader(node.OuterXml);
XmlReader xr = XmlReader.Create(sr);
//Create a StringWriter object to capture the output from the XslCompiledTransform object
StringWriter sw = new StringWriter();
//Perform the transformation
xslt.Transform(xr, null, sw);
//Retrieve the transformed XML from the StringWriter object
string transformedXml = sw.ToString();
UPDATE (thanks for all the answers so far!):
Sorry for my vagueness: by "faster" and more "concise" I mean, am I including any unnecessary steps? Also, I would love a more "readable" solution if someone has one. I use this code in a small part of a web application I'm developing, and I'm about to move it to a large part of the application, so I want to make sure it's as neat as can be before I make the move.
Also, I get the XML from a static class (in a separate data access class library) which communicates with a database. I also manipulate the transformed XML string before shipping it off to a web page. I'm not sure if the input/response streams are still viable in this case.
One more thing: the XML and the XSLT supplied may change (users of the application can make changes to both), so I think I would be forced to compile each time.
Here's code I did for my ASP.NET, which is very similar to yours:
XDocument xDoc = XDocument.Load("output.xml");
XDocument transformedDoc = new XDocument();
using (XmlWriter writer = transformedDoc.CreateWriter())
{
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(XmlReader.Create(new StreamReader("books.xslt")));
transform.Transform(xDoc.CreateReader(), writer);
}
// now just output transformedDoc
If you have a large XSLT you can save the overhead of compiling it at runtime by compiling the XSLT into a .NET assembly when you build your project (e.g. as a post-build step). The compiler to do this is called xsltc.exe and is part of Visual Studio 2008.
In order to load such a pre-compiled XSLT you will need .NET Framework 2.0 SP1 or later installed on your server (the feature was introduced with SP1).
For an example check Anton Lapounov's blog article:
XSLTC — Compile XSLT to .NET Assembly
If pre-compiling the XSLT is not an option you should consider caching the XslCompiledTransform after it is loaded so that you don't have to compile it everytime you want to execute the transform.
Don't have time to do a full example, but some notes:
XML is not the same as System.String. Get it from the class library as XDocument or XmlDocument; finish with it as XDocument or XmlDocument.
You can use the ASP.NET Cache to store the compiled XSL, with a cache dependency on when the .XSLT file changes.
Don't convert the XML to a string then back to XML. Use node.CreateNavigator().ReadSubTree().
Similarly, use XPathNavigator.AppendChild to get an XmlWriter that will write into an XML Document.
Since you mention ASP.NET, the question is whether you can use the response stream directly for your transform output and whether you can use the input stream directly if it is a POST...
I'd rewrite the code like this:
string path = HttpContext.Current.Server.MapPath("/xslt/" + xsltfile.Value);
XmlReader reader = CreateXmlReader(node.OuterXml);
string transformedXml = Transform(path, reader);
private XmlReader CreateXmlReader(string text)
{
StringReader reader = new StringReader(text);
return XmlReader.Create(reader);
}
private string Transform(string xsltPath, XmlReader source)
{
XsltCompiledTransform transformer = new XsltCompiledTransform();
transformer.Load(
xsltPath,
new XsltSettings(true, false),
new XmlUrlResolver());
StringWriter writer = new StringWriter();
transformer.Transform(source, null, writer);
return writer.ToString();
}
The reason why I'd rewrite the code like this is because each block of code now has one and only one purpose. This makes it easier to read and understand. Additionally, the code requires less comments because a lot of information can be inferred from the names of the function and its parameters.

Categories