XSLT not encoding double byte characters - c#

I'm working on a viewer to display xml log files as html using xslt. Everything is going fine exception my localization. The resulting HTML file has a 'ó' where some double byte characters should be. I can't figure out what I am doing wrong.
Here is a a stripped down XSLT file:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/02/xpath-functions">
<xsl:output method="html" version="4.0" encoding="utf-8" indent="yes"/>
<xsl:variable name="language" select="nbklog/#language" />
<xsl:variable name="dictionaryName">
dictionary_<xsl:value-of select="$language"/>.xml
</xsl:variable>
<xsl:variable name="dictionary" select="document($dictionaryName)" />
<xsl:template match="/nbklog">
<html>
<body>
<h2>
<xsl:value-of select="$dictionary//String[#Key=$jobType]" />
</h2>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Here is a dictionary xml file used for localization:
<?xml version="1.0" encoding="utf-8"?>
<Dictionary xml:lang="es-ES">
<String Key="Application">
Applicación
</String>
</Dictionary>
Here is an example xml file to be transformed:
<?xml version="1.0" encoding="utf-8"?>
<nbklog id="51b654d4" jobType="backup" language="es-ES" version="1.0">
<deviceName>c:\</deviceName>
....
</nbklog>
I'm executing the transformation the following c# code:
string theOutputHtml;
using (MemoryStream ms = new MemoryStream()) {
using (XmlTextWriter writer = new XmlTextWriter(ms, Encoding.UTF8)) {
XPathDocument theDocument = new XPathDocument(inXmlFilename);
// Load the style sheet and run the transformation.
XslCompiledTransform theXslTrasform = new XslCompiledTransform();
theXslTrasform.Load(inXsltFilename, XsltSettings.TrustedXslt, null);
theXslTrasform.Transform(theDocument, writer);
ms.Position = 0;
using (StreamReader theReader = new StreamReader(ms)) {
theOutputHtml = theReader.ReadToEnd();
}
}
}
The content of theOutputHtml will have a 'ó' instead of the 'ó'.
EDIT:
Adding this between the and tags in the html string solved my problem:
<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'>

Change new XmlTextWriter(ms, Encoding.ASCII) to new XmlTextWriter(ms, Encoding.UTF8)
Update:
Another possible issue is that although your XML files have an encoding="utf-8" declaration, perhaps the files aren't actually saved with that encoding. Check that all of your XML files' encodings match their declared encodings. Personally, I prefer doing away with declaring the encoding so that it can be automatically be detected instead.

Pretty sure its because you are using the wrong encoding, try this:
using (XmlTextWriter writer = new XmlTextWriter(ms, Encoding.Unicode))

Related

cdata-section-elements not working

I am trying to set a password in an xml file generated via XSLT (using Saxon-HE v9.7.0.14), by setting a global parameter.
The password can contain any characters so it needs to be put in a CDATA section.
I am trying to achieve this by setting the cdata-section-elements attribute of my xslt's xsl:output element to include the name of the password element:
<xsl:output method="xml" indent="yes" cdata-section-elements="password"/>
This is not working. I have included example code, input, xslt, current output and desired output below.
What do I need to change to get the password inside a CDATA section?
Program:
using System;
using System.IO;
using Saxon.Api;
namespace XsltTest {
class Program {
static void Main(string[] args) {
var xslt = new FileInfo(#"transform.xslt");
var input = new FileInfo(#"input.xml");
var output = new FileInfo(#"output.xml");
var processor = new Processor();
var compiler = processor.NewXsltCompiler();
var executable = compiler.Compile(new Uri(xslt.FullName));
var transformer = executable.Load();
var destination = new DomDestination();
using (var inputStream = input.OpenRead()) {
transformer.SetInputStream(inputStream, new Uri(Path.GetTempPath()));
transformer.SetParameter(
new QName("password"),
new XdmAtomicValue("secret"));
transformer.Run(destination);
}
destination.XmlDocument.Save(output.FullName);
}
}
}
Transform.xslt:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes" cdata-section-elements="password"/>
<xsl:param name="password" />
<xsl:template match="#* | node()">
<bar>
<username>
<xsl:value-of select="//username"/>
</username>
<password>
<xsl:value-of select="$password"/>
</password>
</bar>
</xsl:template>
</xsl:stylesheet>
Input.xml:
<?xml version="1.0" encoding="utf-8" ?>
<foo>
<username>john</username>
</foo>
Output.xml:
<bar>
<username>john</username>
<password>secret</password>
</bar>
The password is not put inside a CDATA section.
Desired result:
<bar>
<username>john</username>
<password><![CDATA[secret]]></password>
</bar>
The options on xsl:output affect the actions of the serializer, and if the output is not serialized, they have no effect. You are writing to a DomDestination rather than to a Serializer (and then serializing the DOM using DOM methods, which know nothing about the XSLT xsl:output declaration).
In any case your premise is wrong: "The password can contain any characters so it needs to be put in a CDATA section." Without cdata-section-elements, special characters will be serialized using entity references such as < and &, which should work just fine.
I tested your code and it appears to be working correctly.
The input line
xsltproc --stringparam password "1>2Ä-34" Transform.xslt Input.xml
returns the desired output
<?xml version="1.0"?>
<bar>
<username>john</username>
<password><![CDATA[1>2Ä-34]]></password>
</bar>
Did you miss the input of the password parameter to the XSLT processor to feed the <xsl:param name="password" />?
Michael Kay's answer explained the solution, which was that the cdata-section-elements attribute is only applicable when writing to a Serializer not a DomDestination.
Here's the C# code for doing that:
static void Main(string[] args) {
var xslt = new FileInfo(#"transform.xslt");
var input = new FileInfo(#"input.xml");
var output = new FileInfo(#"output.xml");
var processor = new Processor();
var compiler = processor.NewXsltCompiler();
var executable = compiler.Compile(new Uri(xslt.FullName));
var transformer = executable.Load();
var serializer = new Serializer();
using (var writer = new StreamWriter(output.FullName))
using (var inputStream = input.OpenRead()) {
serializer.SetOutputWriter(writer);
transformer.SetInputStream(inputStream, new Uri(Path.GetTempPath()));
transformer.SetParameter(
new QName("password"),
new XdmAtomicValue("secret"));
transformer.Run(serializer);
}

Visual C# Display XML Web Browser

So I am following a tutorial from here. I have the following code but it simply won't display anything inside the web browser component. The specific instructions I followed are:
"Hi everyone,
I managed to do this using the following strategy:
Download an HTML 1.0 compliant version of defaultss.xsl (I'm using my own)
Create an XMLCompiledTransform object and load the "defaultss.xsl" stylesheet. I actually embedded it is a resource in my assembly and read it from there.
Transform your XML stream using the XMLCompiledTransform into an HTML stream.
Set the WebBrowser.DocumentStream = HTML stream
Remember to "AllowNavigation" otherwise the thing doesn't work.
Hope this helps,
B."
OpenFileDialog OpenCCD = new OpenFileDialog();
OpenFileDialog OpenXSL = new OpenFileDialog();
string xslpath, filepath;
private void button1_Click(object sender, EventArgs e)
{
OpenCCD.ShowDialog();
filepath = OpenCCD.FileName;
}
private void cmd_XSL_Click(object sender, EventArgs e)
{
OpenXSL.ShowDialog();
xslpath = OpenXSL.FileName;
}
private void cmd_View_Click(object sender, EventArgs e)
{
MessageBox.Show("XML Path:" + filepath + "\nXSL Path:" + xslpath);
XslCompiledTransform xsl = new XslCompiledTransform();
xsl.Load(xslpath);
MemoryStream ms = new MemoryStream();
xsl.Transform(filepath, null, ms);
webBrowser1.DocumentStream = ms;
}
The xml is pretty long so here is a piece of it:
<?xml version="1.0" encoding="UTF-8"?>
<CDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:hl7-org:v3 http://xreg2.nist.gov:8080/hitspValidation/schema/cdar2c32/infrastructure/cda/C32_CDA.xsd" xmlns="urn:hl7-org:v3" xmlns:mif="urn:hl7-org:v3/mif">
<realmCode code="US"/>
<typeId root="2.16.840" extension="PO"/>
<templateId root="2.16"/>
<templateId root="2.17"/>
<id root="2.16.84" extension="E5"/>
<code codeSystem="2.16.88" codeSystemName="" code="3" displayName="TITLE"/>
<title>TITLE</title>
<effectiveTime value="2925"/>
<confidentialityCode code="Y" codeSystem=""/>
<recordTarget>
<patientRole>
<id root="2.16.84" extension="215"/>
<addr use="P">
<streetAddressLine>123 GREEN TRAIL RD</streetAddressLine>
<city>BIRMINGHAM</city>
<state>AL</state>
<postalCode>35211</postalCode>
<country>USA</country>
</addr>
<telecom use="H" value="tel:000000000"/>
<patient>
<name>
<given qualifier="L">ADAM</given>
<family qualifier="R">EVERYMAN</family>
</name>
<ethnicGroupCode codeSystem="2.16.84" codeSystemName="Race" displayName="Not Hispanic or Latino"/>
<languageCommunication>
<languageCode code="eng"/>
</languageCommunication>
</patient>
</patientRole>
</recordTarget>
XSL is also long so here is a piece of it:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:n3="http://www.w3.org/1999/xhtml" xmlns:n1="urn:hl7-org:v3" xmlns:n2="urn:hl7-org:v3/meta/voc" xmlns:voc="urn:hl7-org:v3/voc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="html" indent="yes" version="4.01" encoding="ISO-8859-1" doctype-public="-//W3C//DTD HTML 4.01//EN"/>
<xsl:variable name="tableWidth">50%</xsl:variable>
<xsl:variable name="title">
<xsl:choose>
<xsl:when test="/n1:CDocument/n1:title">
<xsl:value-of select="/n1:CDocument/n1:title"/>
</xsl:when>
<xsl:otherwise>CDocument</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates select="n1:CDocument"/>
</xsl:template>
The solution that I found was to use the following code instead. This code, saves a result.html and renders that inside the web browser control.
XslCompiledTransform myXslTrans = new XslCompiledTransform();
myXslTrans.Load(xslpath);
string directoryPath = Path.GetDirectoryName(filepath);
myXslTrans.Transform(filepath, directoryPath+"result.html");
webBrowser1.Navigate(directoryPath+"result.html");

White space cannot be stripped from input documents that have already been loaded. Provide the input document as an XmlReader instead

I want to transform a XML document, but having a problem.
My XSLT looks like this:
<?xml version="1.0" encoding="iso-8859-1" ?>
<xsl:stylesheet version="1.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<xsl:apply-templates select="address" />
</xsl:template>
<xsl:template match="address">
<xsl:value-of select="#street" />
<xsl:value-of select="#housenr" />
<xsl:value-of select="#zipcode" />
<xsl:value-of select="#city" />
<xsl:value-of select="#country" />
</xsl:template>
</xsl:stylesheet>
And the XML document I want to transform looks like this:
<address id="4" type="1"
typename="Postadres"
street="pak street"
housenr="420"
zipcode="42000"
city="Nill"
country="Lahore"
kix="" />
Here is the code I've written:
public static string Transform(XmlDocument doc, XmlDocument stylesheet)
{
var transform = new System.Xml.Xsl.XslCompiledTransform();
XmlDocument domOutput = new XmlDocument();
stylesheet.PreserveWhitespace = false;
transform.Load(stylesheet); // compiled stylesheet
MemoryStream oStream = new MemoryStream();
var writer = new System.IO.StringWriter();
transform.Transform(doc, (XsltArgumentList)null, oStream);
domOutput.Load(oStream);
return writer.ToString();
}
The following line throws an exception
transform.Transform(doc, (XsltArgumentList)null, oStream);
Exception message:
White space cannot be stripped from input documents that have already been loaded. Provide the input document as an XmlReader instead.
Can you tell me what I am doing wrong?
Thanks in advance!
I solved it. Actually "XslCompiledTransform.Transform" takes XmlReader as first Parameter and i was passing XmlDocument in First Paramenter.
Here is the code.
public static string Transform(XmlDocument doc, XmlDocument stylesheet)
{
try
{
System.Xml.Xsl.XslCompiledTransform transform = new System.Xml.Xsl.XslCompiledTransform();
transform.Load(stylesheet); // compiled stylesheet
System.IO.StringWriter writer = new System.IO.StringWriter();
XmlReader xmlReadB = new XmlTextReader(new StringReader(doc.DocumentElement.OuterXml));
transform.Transform(xmlReadB, null, writer);
return writer.ToString();
}
catch (Exception ex)
{
throw ex;
}
}

Add <?xml version="1.0" ?> to the top of a xml file after xsl transform

I have successfully been able to transform a simple xml file with data to another xml file (excel template) using a xsl template, this is what my xsl file looks like:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" standalone="yes"/>
<xsl:template match="/">
<xsl:processing-instruction name="mso-application">
<xsl:text>progid="Excel.Sheet"</xsl:text>
</xsl:processing-instruction>
...(stuff here)...
</xsl:template>
</xsl:stylesheet>
The resulting xml file is written out correctly BUT with the exception of including
<?xml version="1.0"?>
at the top of the file. How can I get it to appear at the top?
Currently my resulting xml file starts with:
<?mso-application progid="Excel.Sheet"?>
...(rest of file)...
But what I need it to do is:
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
.(rest of file)...
I'm doing this transform through a windows form with the following code:
XPathDocument myXPathDoc = new XPathDocument(xmlfile);
XslCompiledTransform myXslTrans = new XslCompiledTransform();
myXslTrans.Load(xslfile);
XmlTextWriter myWriter = new XmlTextWriter(xmlexcelfile, null);
myWriter.Formatting = Formatting.Indented;
myWriter.Namespaces = true;
myXslTrans.Transform(myXPathDoc, null, myWriter);
myWriter.Close();
I've tried playing around with the xsl:output standalone="yes/no", as well as omit-xml-declaration="no". I've also tried (in the C#) code adding myWriter.WriteStartDocument(); before transforming but that was not allowed. I have tried searching online for this as well and keep coming back to the standalone="yes" but that isn't working. Is there something I am missing here? Oh and in case you are wondering why I need to have the
<?xml version="1.0"?>
at the top of the resulting file, it's because when opening the xml file with excel, excel doesn't recognize it correctly but if it is included then excel opens it correctly...
You can do this
<xsl:output method="xml" indent="yes" omit-xml-declaration="no" />
or something similar to this using XmlWriterSettings
Edit: Added more code. Previous was missing some parts
XmlWriterSettings writerSettings = null;
XsltArgumentList transformationArguments = null;
XslCompiledTransform transformer = null;
MemoryStream memoryStream = null;
XPathDocument xPathDocument = null;
StringBuilder sb = null;
XmlWriter writer = null;
XmlDocument resultXml = null;
try
{
writerSettings = new XmlWriterSettings();
writerSettings.OmitXmlDeclaration = false; // This does it
writerSettings.Indent = true;
transformationArguments = new XsltArgumentList();
transformer = new XslCompiledTransform();
memoryStream = new MemoryStream(System.Text.Encoding.Default.GetBytes(xml.OuterXml));
xPathDocument = new XPathDocument(new StreamReader(memoryStream));
sb = new StringBuilder();
// give the settings to the writer here
writer = XmlWriter.Create(sb, writerSettings);
// this is not mandatory, obviously, just passing parameters to my xslt file
foreach (KeyValuePair<string, object> parameter in parameters)
{
transformationArguments.AddParam(parameter.Key, string.Empty, parameter.Value);
}
using (Stream strm = Assembly.GetExecutingAssembly().GetManifestResourceStream("Lib.XSLTFile1.xslt"))
using (XmlReader reader = XmlReader.Create(strm))
{
transformer.Load(reader);
transformer.Transform(xPathDocument, transformationArguments, writer);
}
resultXml = new XmlDocument();
resultXml.LoadXml(sb.ToString());
// for testing only
File.AppendAllText(#"Your path goes here\result.xml", resultXml.OuterXml);
}
catch (Exception)
{
throw;
}
This is how I do it, but this code is specifically written to create an instance of a XmlDocument. I'm sure you can adapt to your needs.

XSLT transformation does not return anything

I am trying to create a small code generator based upon XSLT transformation. I am rather new to XSLT, and it seems that I have made error (not sure where) in my transformations. I have two transformation (main and util), the metadata is pulled from XML file (it stores information about table names, which will be used for class generation- table name = class name; column name = field name ). Here are my transformations:
Main transformation
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
xmlns:dbs="http://kadgen/DatabaseStructure">
<xsl:import href="..\MySolution\UtilTemplates.xslt"/>
<xsl:output method="text" encoding="UTF-8" indent="yes"/>
<xsl:param name="Name"/>
<xsl:param name ="filedName"/>
<xsl:template match="/">
<xsl:apply-templates select=
"//dbs:DataStructure//dbs:Table[#Name='Customer']"
mode="BuildClasses" />
</xsl:template>
<xsl:template match="dbs:Table" mode="BuildClasses">
<xsl:call-template name="Header"/>
Public Class <xsl:value-of select="#Name"/>
{
<xsl:call-template name="ClassConstructors"/>
<xsl:call-template name="ClassLevelDeclarations"/>
<xsl:call-template name="FieldAccessProperties"/>
}
</xsl:template>
<xsl:template name="ClassConstructors">
</xsl:template>
<xsl:template name="ClassLevelDeclarations">
</xsl:template>
<xsl:template name="FieldAccessProperties">
</xsl:template>
</xsl:stylesheet>
Here is the util transformation:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="text"/>
<xsl:template name="Header">
using System;
using System.Collections.Generic;
using System.Xml;
using System.Linq;
using System.Text;
</xsl:template>
</xsl:stylesheet>
Here is part of my XML file:
<?xml version="1.0" encoding="utf-8" ?>
<dbs:MetaDataRoot FreeForm="true" xmlns:dbs="http://kadgen/DatabaseStructure">
<dbs:DataStructures>
<dbs:DataStructure Name="ASPDatabase">
<dbs:Tables>
<dbs:Table Name="Customer" OriginalName="Customer">
<dbs:TableColumns>
<dbs:TableColumn Name="CustomerID" NETType="int" IsPrimaryKey="true" />
<dbs:TableColumn Name="Name" NETType="string" IsPrimaryKey="false"/>
</dbs:TableColumns>
<dbs:TableConstraints>
<dbs:PrimaryKey>
<dbs:PKField Name="CustomerID"/>
</dbs:PrimaryKey>
</dbs:TableConstraints>
</dbs:Table>
</dbs:Tables>
</dbs:DataStructure>
</dbs:DataStructures>
</dbs:MetaDataRoot>
Here is how I start transformation:
XslCompiledTransform myXslTrans = new XslCompiledTransform();
myXslTrans.Load("xslt transformation location");
myXslTrans.Transform("XML source location", "Empty class file location");
After executing above code, only thing I get is empty cs file. It may seem robust but please, go through it and help me with this.
Thanks.
Have you tried debugging your XSLT files with VS XSLT debugger?
Looks like it generates correct output.
This is working for me but I made a couple of small changes and fixed your XML doc.
Here is my test app.
private static void Main(string[] args)
{
var myXslTrans = new XslCompiledTransform();
var doc = new XmlDocument();
doc.LoadXml(GetResourceTextFile("ProjectName.MainTransform.xslt"));
myXslTrans.Load(doc);
var sb = new StringBuilder();
var sw = new StringWriter(sb);
var xsltArgs = new XsltArgumentList();
xsltArgs.AddParam("Name", "", "test name");
xsltArgs.AddParam("filedName", "", "test filed name");
var docXml = new XmlDocument();
docXml.LoadXml(GetResourceTextFile("ProjectName.Test.xml"));
myXslTrans.Transform(docXml, xsltArgs, sw);
var test = sw.ToString();
}
public static string GetResourceTextFile(string filename)
{
string result = string.Empty;
var assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(filename))
{
if (stream != null)
{
using (var sr = new StreamReader(stream))
{
result = sr.ReadToEnd();
}
}
}
return result;
}
The major differences I made were adding XSLT arguments and loading the embedded files into XmlDocuments first. I can't reproduce the blank output so I can't be sure what the root cause of your issue is.

Categories