I am using the treeview control included in asp.net 2.0.
I want to use an xsl file that I created (test3.xslt).
Why isn't the Treeview picking up the changes to the tree made with the xsl (in tw, I think) and displaying them?
tw has the changes made by the xslt transform...
The DataSourceID for my treeview is my xmldatasource (xmldatasource1).
Thanks,
blue
argsList.AddParam("Groups_From_Logged_In_User","",myLocalGroups);
XslCompiledTransform xslTransform = new XslCompiledTransform();
xslTransform.Load("C:\\ANewBeginning3\\test3.xslt");
StringWriter tw = new StringWriter();
using (StreamWriter sw = new StreamWriter("C:\\ANewBeginning3\\output.xml"))
{
xslTransform.Transform(xmldoc.CreateNavigator(), argsList, tw);
XmlDataSource1.Data = tw.ToString();
}
XmlDataSource1.DataBind();
}
I figured it out...
First, xmldatasource blocks any other xml if xmldatasource.DataFile is specified. I was using xmldatasource.data above AND specified the DataFile as well. (see http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.xmldatasource.data.aspx )
Second, do not specify the xslt file in xmldatasource either. I was trying to both transform it (using xslTransform) AND specify the same stylesheet in xmlDatasource.TransFormFile (http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.xmldatasource.transformfile.aspx). Don't do both (unless you know why you're doing it.)
Related
I'm using Asp.net to make a transformation in XML using XSLT by C# code as follows.
protected void Page_Load(object sender, EventArgs e)
{
string strXSLTFile = Server.MapPath("EmployeeXSLT.xslt");
string strXMLFile = Server.MapPath("Employess.xml");
XmlReader reader = XmlReader.Create(strXMLFile);
XslCompiledTransform objXSLTransform = new XslCompiledTransform();
objXSLTransform.Load(strXSLTFile);
StringBuilder htmlOutput = new StringBuilder();
TextWriter htmlWriter = new StringWriter(htmlOutput);
objXSLTransform.Transform(reader, null, htmlWriter);
ltRss.Text = htmlOutput.ToString();
reader.Close();
}
and for full example with (Asp.net, XSLT and XML) follow this link
Doing XSLT Transformation in ASP.Net
Now I need to change the Xpath value of the XSLT file. I conduct a search to find out how to do this. finally, I found tow concepts to affect the XSLT file. However, no examples provided on how to apply these concepts to change XSLT "match" or "for-each select" where I need to add a variable for changeable Xpath.
the first one:
using so-called Dynamic XPath Evaluation
the second one:
using so-called XSLT Parameters
I need to know how can I change the XSLT "match" using C# code to meet specific selection.
You can use an XPathNavigator to compile an xpath expression then go through the matching nodes in your c# code.
// Create and compile the XPathExpression
string _xPathExpression = "/Data/Client[Id = 123]";
XPathExpression exprXPathCompiled
= xmlDocInputNavigator.Compile(_xPathExpression);
// Load the Stylesheet
XsltSettings settings = new XsltSettings();
XslCompiledTransform xsltTemplate = new XslCompiledTransform();
xsltTemplate.Load(_stylesheetFileName, settings, new XmlUrlResolver());
// Create an iterator to loop through the matching nodes
XPathNodeIterator iterator = xmlDocInputNavigator.Select(exprXPathCompiled);
StreamWriter fileOutput = null;
while (iterator.MoveNext())
{
//...
XPathNavigator docs
It would help if you explained the problem you are trying to solve, rather than the method you want to use to solve it.
An XSLT stylesheet is an XML document, so you can always transform it using XSLT (with a so-called "meta-stylesheet").
With XSLT 3.0 (not available from Microsoft, but available to C# users via the Saxon library) you can parameterize a stylesheet using "shadow attributes", for example
<xsl:template _match="{$pattern}"/>
where $pattern is a stylesheet parameter declared as
<xsl:param name="pattern" static="yes"/>
so that a value can be supplied by the calling application.
You can also of course use conventional (run-time) parameters in a match pattern of the form
<xsl:template match="*[#id=$requestedId]"/>
XSLT 1.0 doesn't allow parameter references in match patterns, unfortunately. Some XSLT 1.0 processors don't enforce this restriction but I don't know if that's the case for the Microsoft processor.
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.
I'm trying to build an executable which applies XSLT transforms onto a large number XML files. Now my problem is that I'd like to include/refer to the XSLT file stored with my C# VS 2010 solution, so that when I repackage this for another machine, I don't have to copy across the XSLT files. Is this possible?
string xslFile = "C:\template.xslt";
string xmlFile = "C:\\file00324234.xml";
string htmlFile = "C:\\output.htm";
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(xslFile);
transform.Transform(xmlFile, htmlFile);
You can include the XSLT as an Embedded Resource into your assembly as described here:
How to embed an XSLT file in a .NET project to be included in the output .exe?
Once embedded, you can use the transform as follows:
using(Stream stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream("YourAssemblyName.filename.xslt"))
{
using (XmlReader reader = XmlReader.Create(stream))
{
XslCompiledTransform transform = new XslCompiledTransform ();
transform.Load(reader);
// use the XslTransform object
}
}
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.
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.