I am trying to use a XslCompiledTransform, and use the output as a XPathDocument.
Any Ideas?
Mr. Jones's answer was very helpful for me, but I found that the last line didn't work. I ended up doing this:
XslCompiledTransform xsl = new XslCompiledTransform();
xsl.Load(filePath);
StringWriter stringWriter = new StringWriter();
XmlWriter xmlWriter = XmlTextWriter.Create(stringWriter);
xsl.Transform(xPathDoc, xmlWriter);
String newXml = stringWriter.ToString();
StringReader stringReader = new StringReader(newXml);
xPathDoc = new XPathDocument(stringReader);
(Here, xPathDoc is an XPathDocument that has already been initialized from an XmlReader.)
Send the transform to an XmlTextWriter based on a StringWriter. Then instance the XPathDocument by retreiving the XML string from the StringWriter.
var sw = new StringWriter();
var xtw = new XmlTextWriter(sw);
myTransform.Transform(myXml, xtw);
var xpd = new XPathDocument(sw.ToString());
Its not the most memory efficient mechanism but will be adequate for most needs. A similar approach would be use a MemoryStream instead of a StringWriter but its a little messy by comparison.
A slightly better form of David M. Anderson's answer is below: it does not suffer from potential resource leaks; otherwise it is the same.
private static XPathDocument TransformToXPathDocument(string styleSheetPath,
IXPathNavigable xPathDoc)
{
var xsl = new XslCompiledTransform();
xsl.Load(styleSheetPath);
using(var stringWriter = new StringWriter())
{
using(XmlWriter xmlWriter = XmlWriter.Create(stringWriter))
{
xsl.Transform(xPathDoc, xmlWriter);
}
using(var reader = new StringReader(stringWriter.ToString()))
{
return new XPathDocument(reader);
}
}
}
Related
I have to transform .xml two times with different .xslt files and I know how to transform it once, but don't have idea, how to repeat it, because when I my output was something like html string and i changed my code, by using XmlWriter instead of StringWriter (commented), but it generates an empty Xml so it can't be transferred again.
public static HtmlString RenderXml(this HtmlHelper helper, string xml, string transformXsltPath, string xsltPath)
{
xml = System.IO.File.ReadAllText(("C:/Users/Student/Documents/Visual Studio 2010/Projects/MvcApplication2/MvcApplication2/schemat.xsd"));
XsltArgumentList args = new XsltArgumentList();
XslCompiledTransform t = new XslCompiledTransform();
t.Load(transformXsltPath);
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;;
using (XmlReader reader = XmlReader.Create(new StringReader(xml), settings))
{
//StringWriter writer = new StringWriter();
XmlWriter writer = XmlWriter.Create(new StringWriter());
t.Transform(reader, args, writer);
XslCompiledTransform t2 = new XslCompiledTransform();
t2.Load(xsltPath);
XmlReader reader2 = XmlReader.Create(new StringReader(writer.ToString()), settings);
StringWriter writer2 = new StringWriter();
t2.Transform(reader2, args, writer2);
HtmlString htmlString = new HtmlString(writer2.ToString());
return htmlString;
}
}
I'm writing a web service in .NET C# that takes in an object, converts it to xml, applies an XSLT template, runs the transformation, and returns an MS work file.
Here is the code for the function:
public static HttpResponseMessage Transform(object data)
{
var response = new HttpResponseMessage(HttpStatusCode.OK);
StringWriter stringWriter = new StringWriter();
XmlWriter xmlWriter = XmlWriter.Create(stringWriter);
var applicationDirectory = AppDomain.CurrentDomain.BaseDirectory;
var xsltPath = applicationDirectory + #"\Reporting\Files\Template.xslt";
var templatePath = applicationDirectory + #"\Reporting\Files\Template.docx";
var xmlObject = new System.Xml.Serialization.XmlSerializer(data.GetType());
MemoryStream stream;
using (stream = new MemoryStream())
{
var sw = new StreamWriter(stream);
xmlObject.Serialize(stream, data);
stream.Position = 0;
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(xsltPath);
using (XmlReader xmlReader = XmlReader.Create(stream))
{
transform.Transform(xmlReader, xmlWriter);
XmlDocument newWordContent = new XmlDocument();
newWordContent.LoadXml(stringWriter.ToString());
var outputPath = applicationDirectory + #"\Reporting\Temp\temp.docx";
System.IO.File.Copy(templatePath, outputPath, true);
using (WordprocessingDocument output = WordprocessingDocument.Open(outputPath, true))
{
Body updatedBodyContent = new Body(newWordContent.DocumentElement.InnerXml);
output.MainDocumentPart.Document.Body = updatedBodyContent;
output.MainDocumentPart.Document.Save();
}
response.Content = new StreamContent(new FileStream(outputPath, FileMode.Open, FileAccess.Read));
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = outputPath;
}
}
return response;
}
When I make a request, it gives me a word file without the data.
I put a breakpoint at using (XmlReader xmlReader = XmlReader.Create(stream)).
After running that line, xmlReader has a value of {None}.
I'm also trying to avoid creating an XML file for efficiency(Hence MemoryStream).
Any idea why this isn't working? And is there a better way of accomplishing this?
Thanks,
Gerson
What happens if you change this:
Body updatedBodyContent = new Body(newWordContent.DocumentElement.InnerXml);
to this:
Body updatedBodyContent = new Body(newWordContent.InnerXml);
or this:
Body updatedBodyContent = new Body(newWordContent.DocumentElement.OuterXml);
The way you have it there would cause the outer element of the transformed XML to be omitted, and I doubt that's what you want (though can't say for sure because you've shown us neither the input XML or the XSLT.
I am modifying some legacy code to try to eliminate warnings. XmlDataDocument and XslTransform both generate warnings that they are obsolete. In the case of XslTransform the suggested replacement is XslCompiledTransform, but no replacement is suggested for XmlDataDocument.
How can I change this code to eliminate warnings in .NET 4:
var xmlDoc = new System.Xml.XmlDataDocument(myDataSet);
var xslTran = new System.Xml.Xsl.XslTransform();
xslTran.Load(new XmlTextReader(myMemoryStream), null, null);
var sw = new System.IO.StringWriter();
xslTran.Transform(xmlDoc, null, sw, null);
XDocument doc = new XDocument();
using (XmlWriter xw = doc.CreateWriter())
{
myDataSet.WriteXml(xw);
xw.Close();
}
XslCompiledTransform proc = new XslCompiledTransform();
using (XmlReader xr = XmlReader.Create(myMemoryStream))
{
proc.Load(xr);
}
string result;
using (StringWriter sw = new StringWriter())
{
proc.Transform(doc.CreateNavigator(), null, sw); // needs using System.Xml.XPath;
result = sw.ToString();
}
should do I think. Of course I have only used that MemoryStream for loading the stylesheet and the StringWriter for sending the transformation result to as you code snippet used those. Usually there are other input sources or output destinations like files, or streams or Textreader.
XMLDocument is really your main option. I'm not 100% sure what you're trying to do with the code block you've posted, but you can give something like this a shot:
public void DoThingsWithXml()
{
string strXdoc = src.GetTheXmlString(); // however it is you do it
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(strXdoc);
// The other things you need to do
}
I am using the following code to create an xml document -
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
new XmlSerializer(typeof(docket)).Serialize(Console.Out, i, ns);
this works great in creating the xml file with no namespace attributes. i would like to also have no encoding attribute in the root element, but I cannot find a way to do it. Does anyone have any idea if this can be done?
Thanks
Old answer removed and update with new solution:
Assuming that it's ok to remove the xml declaration completly, because it makes not much sense without the encoding attribute:
XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("", "");
using (XmlWriter writer = XmlWriter.Create(Console.Out, new XmlWriterSettings { OmitXmlDeclaration = true}))
{
new XmlSerializer(typeof (SomeType)).Serialize(writer, new SomeType(), ns);
}
To remove encoding from XML header pass TextWriter with null encoding to XmlSerializer:
MemoryStream ms = new MemoryStream();
XmlTextWriter w = new XmlTextWriter(ms, null);
s.Serialize(w, vs);
Explanation
XmlTextWriter uses encoding from TextWriter passed in constructor:
// XmlTextWriter constructor
public XmlTextWriter(TextWriter w) : this()
{
this.textWriter = w;
this.encoding = w.Encoding;
..
It uses this encoding when generating XML:
// Snippet from XmlTextWriter.StartDocument
if (this.encoding != null)
{
builder.Append(" encoding=");
...
string withEncoding;
using (System.IO.MemoryStream memory = new System.IO.MemoryStream()) {
using (System.IO.StreamWriter writer = new System.IO.StreamWriter(memory)) {
serializer.Serialize(writer, obj, null);
using (System.IO.StreamReader reader = new System.IO.StreamReader(memory)) {
memory.Position = 0;
withEncoding= reader.ReadToEnd();
}
}
}
string withOutEncoding= withEncoding.Replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>", "");
Credit to this blog for helping me with my code
http://blog.dotnetclr.com/archive/2008/01/29/removing-declaration-and-namespaces-from-xml-serialization.aspx
here's my solution, same idea, but in VB.NET and a little clearer in my opinion.
Dim sw As StreamWriter = New, StreamWriter(req.GetRequestStream,System.Text.Encoding.ASCII)
Dim xSerializer As XmlSerializer = New XmlSerializer(GetType(T))
Dim nmsp As XmlSerializerNamespaces = New XmlSerializerNamespaces()
nmsp.Add("", "")
Dim xWriterSettings As XmlWriterSettings = New XmlWriterSettings()
xWriterSettings.OmitXmlDeclaration = True
Dim xmlWriter As XmlWriter = xmlWriter.Create(sw, xWriterSettings)
xSerializer.Serialize(xmlWriter, someObjectT, nmsp)
Here's a quick question I've been banging my head against today.
I'm trying to convert a .Net dataset into an XML stream, transform it with an xsl file in memory, then output the result to a new XML file.
Here's the current solution:
string transformXML = #"pathToXslDocument";
XmlDocument originalXml = new XmlDocument();
XmlDocument transformedXml = new XmlDocument();
XslCompiledTransform transformer = new XslCompiledTransform();
DataSet ds = new DataSet();
string filepath;
originalXml.LoadXml(ds.GetXml()); //data loaded prior
StringBuilder sb = new StringBuilder();
XmlWriter writer = XmlWriter.Create(sb);
transformer.Load(transformXML);
transformer.Transform(originalXml, writer); //no need to select the node
transformedXml.LoadXml(sb.ToString());
transformedXml.Save(filepath);
writer.Close();
Here's the original code:
BufferedStream stream = new BufferedStream(new MemoryStream());
DataSet ds = new DataSet();
da.Fill(ds);
ds.WriteXml(stream);
StreamReader sr = new StreamReader(stream, true);
stream.Position = 0; //I'm not certain if this is necessary, but for the StreamReader to read the text the position must be reset.
XmlReader reader = XmlReader.Create(sr, null); //Problem is created here, the XmlReader is created with none of the data from the StreamReader
XslCompiledTransform transformer = new XslCompiledTransform();
transformer.Load(#"<path to xsl file>");
transformer.Transform(reader, null, writer); //Exception is thrown here, though the problem originates from the XmlReader.Create(sr, null)
For some reason in the transformer.Transform method, the reader has no root node, in fact the reader isn't reading anything from the StreamReader.
My questions is what is wrong with this code? Secondarily, is there a better way to convert/transform/store a dataset into XML?
Edit: Both answers were helpful and technically aku's was closer. However I am leaning towards a solution that more closely resembles Longhorn's after trying both solutions.
I'm not sure but it seems that you didn't reset position in stream before passing it to XmlReader. Try to seek at the beginning of your stream before trying to read from it. Also it may be necessary to close\flush stream after you wrote some data to it.
EDIT:
Just tried following code and it worked perfectly:
BufferedStream stream = new BufferedStream(new MemoryStream());
stream.Write(Encoding.ASCII.GetBytes("<xml>foo</xml>"), 0, "<xml>foo</xml>".Length);
stream.Seek(0, SeekOrigin.Begin);
StreamReader sr = new StreamReader(stream);
XmlReader reader = XmlReader.Create(sr);
while (reader.Read())
{
Console.WriteLine(reader.Value);
}
stream.Close();
You must select the root node. This doesn't use Datasets, but I use this function everyday and it works great.
System.Xml.XmlDocument orgDoc = new System.Xml.XmlDocument();
orgDoc.LoadXml(orgXML);
// MUST SELECT THE ROOT NODE
XmlNode transNode = orgDoc.SelectSingleNode("/");
System.Text.StringBuilder sb = new System.Text.StringBuilder();
XmlWriter writer = XmlWriter.Create(sb);
System.IO.StringReader stream = new System.IO.StringReader(transformXML);
XmlReader reader = XmlReader.Create(stream);
System.Xml.Xsl.XslCompiledTransform trans = new System.Xml.Xsl.XslCompiledTransform();
trans.Load(reader);
trans.Transform(transNode, writer);
XmlDocument doc = new XmlDocument();
doc.LoadXml(sb.ToString());
return doc;
please look it and use..
using (MemoryStream memStream = new MemoryStream())
{
memStream.Write(Encoding.UTF8.GetBytes(xmlBody), 0, xmlBody.Length);
memStream.Seek(0, SeekOrigin.Begin);
using (StreamReader reader = new StreamReader(memStream))
{
// xml reader setting.
XmlReaderSettings xmlReaderSettings = new XmlReaderSettings()
{
IgnoreComments = true,
IgnoreWhitespace = true,
};
// xml reader create.
using (XmlReader xmlReader = XmlReader.Create(reader, xmlReaderSettings))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(LoginInfo));
myObject = (LoginInfo)xmlSerializer.Deserialize(xmlReader);
}
}
}