Transform XML into HTML using XSLT - c#

I saw several questions related to XML, XSLT and HTML on stackoverflow, but I beleive my question is a little different. Here is what I need:
I need to send an email to my customers. The wordings of the email can differ based upon the scenario. Each scenario has a corresponding format saved in the database. For example, one scenario might require this email:
Scenario 1: We have opened Ticket XXX/Reference Number XXX for your call on XXX. Kindly call us at XXX to track progress.
Another scenario might required this email:
Scenario 2: Thanks for your interest in our Product XXX. As discussed we will send our representative on XXX to your office located at XXX.
Also, the format might need to be altered a bit depending upon data availability. e.g. if I need to send email corresponding to scenario 1, and I don't have Reference Number available, I want to remove the reference number part completely on the fly (not in database) i.e. I want something like this:
Scenario 3: We have opened Ticket XXX for your call on XXX. Kindly call us at XXX to track progress.
The formats for scenarios 1 and 2 are stored in the database as XSLT corresponding to the strings you see above. Format for Scenario 3 has to be produced on the fly. The XXX part has to be replaced with actual data. This data is available in an XML serializable object that I have.
I want to serialize this object, produce an XML in memory, modify the XSLT a little (on the fly) to reflect the data I have, transform the XML in memory to HTML using the XSLT for the scenario and then pass the HTML as a string parameter to an email method I have. The email part works. I need to work on the Object->XML in memory->Slight XSLT modification-> HTML using appropriate XSLT.
I would appreciate if you can include code examples and not just the approach I need to follow.
EDIT:
Here is the working code:
using (xsltStream = new MemoryStream(emailInfo.Body))
{
// Create an XmlReader from the Stream
XmlReader reader = XmlReader.Create(xsltStream);
// Create and load the transform with document function enabled.
XslCompiledTransform transform = new XslCompiledTransform();
XsltSettings settings = new XsltSettings();
settings.EnableDocumentFunction = true;
transform.Load(reader, settings, null);
// Execute the transformation.
transform.Transform(doc, writer);
}

The formats for scenarios 1 and 2 are stored in the database as XSLT
I think I would be quite inclined to store the formats as XML rather than as XSLT:
<message>Thanks for your interest in our Product <product/>. As discussed we will send our representative on <date/> to your office located at <officeLocation/>.</message>
Then you use a standard stylesheet to transform this document, using data from another document.
Having said this, I only recommend this because I did it myself the way you are describing and regret it, as it's too difficult to make changes or introduce new variations.

Based upon comments from #harpo, #Alexei Levenkov and #Alejandro, I was able to work out a working version of the code which uses multiple templates. Since I can't mark the comments as answers, I will mark this as answer and add the code in my question.
using (xsltStream = new MemoryStream(emailInfo.Body))
{
// Create an XmlReader from the Stream
XmlReader reader = XmlReader.Create(xsltStream);
// Create and load the transform with document function enabled.
XslCompiledTransform transform = new XslCompiledTransform();
XsltSettings settings = new XsltSettings();
settings.EnableDocumentFunction = true;
transform.Load(reader, settings, null);
// Execute the transformation.
transform.Transform(doc, writer);
}

Related

Is there a way to export the reading order in tagged PDF(Accessible PDF)?

I'm trying to create a validation tool using the iText7, to compare the reading order and tagging order from the tagged PDF. Im new to iText.
I have used the below code in c# to extract the tagging structure and save it as xml.
Ref: (Get marked content using the MCID content)
FileStream outXml = new FileStream("pdf_content.xml",FileMode.CreateNew);
TaggedPdfReaderTool tool = new TaggedPdfReaderTool(pdfoc);
tool.SetRootTag("root");
tool.ConvertToXml(outXml);
outXml.Close();
I expect to export the reading order to Xml or other format.
No.
Reading order is a human concept, and might be different from person to person.
Have a look at the following example:
The red parts are snippets that are relevant to the story, but they break the normal layout.
Do you read them first?
Do you read them as you are passing them in top to bottom, left-to-right reading order?
Do you read them last?
Reading order (in the general case) needs human verification at least.

Using XML to Store Colours and Strings in Unity

I'm building an application where the user needs to be able to change the font colour and size (and the colour of the main camera), plus input an 'unlimited' amount of other data.
I'll admit that I've never used XML before, and am a relative beginner to C# as well. I've done a couple of days of searching on this topic already and the tutorials were all either writing from the wrong language or too vague in their explanations for me to completely understand what I was doing (I've included a list of the links I visited at the end of this question).
Ideally, I'd want to save to two locations, with the following format (apologies for the actual data - I'm not sure of the format some of it saves in):
Application.persistentDataPath, "prefs.xml"
<settings>
<font>
<colour>#FFFFFFFF</colour>
<size>14</size>
</font>
<camera>
<colour>#00000000</colour>
</camera>
</settings>
Application.persistentDataPath, "data.xml"
<data>
<section1>
<item1>
<date>01/01/2001</date>
<details>Details here</details>
<imagepath>Application.persistentDataPath, "image1.jpg"</imagepath>
</item1>
<item2>
<date>03/01/2001</date>
<details>Details here</details>
</item2>
</section1>
<section2>
<item1>
<date>02/01/2001</date>
<details>Details here</details>
</item1>
</section2>
</data>
To choose the colours, I'm using a package from the asset store called Color Picker and using two instances of this, with their game objects named as FontPicker and BackgroundPicker. I know that the next two scripts are completely over the place, but I'm putting them in as reference to what I've fiddled around with so far and what my variable names look like (script mainly edited using the YouTube video linked as reference). The code I currently have in my Settings.cs script is as follows:
public class Settings : MonoBehaviour {
public Color SelectedColor {get; set;}
public void Write (string fileName) {
using (var stream = new FileStream(fileName, FileMode.Create)) {
XmlSerializer XML = new XmlSerializer(typeof(ColorPicker));
XML.Serialize(stream, this);
}
}
public void FontColour () {
var FontPicker = GameObject.Find("FontPicker").GetComponent(ColorPicker);
// I get the following compiler errors in the Unity editor:
// Assets/Scripts/Settings.cs(23,77): error CS0119: Expression denotes a `type', where a `variable', `value' or `method group' was expected
// Assets/Scripts/Settings.cs(23,64): error CS1502: The best overloaded method match for `UnityEngine.GameObject.GetComponent(System.Type)' has some invalid arguments
// Assets/Scripts/Settings.cs(23,64): error CS1503: Argument `#1' cannot convert `object' expression to type `System.Type'
Color = ColorPicker.SelectedColor;
// Assets/Scripts/Settings.cs(24,37): error CS0120: An object reference is required to access non-static member `ColorPicker.SelectedColor'
// These same compiler errors are present in the next function
}
public void BackgroundColour () {
var BackgroundPicker = GameObject.Find("BackgroundPicker").GetComponent(ColorPicker);
Color = ColorPicker.SelectedColor;
}
}
I was hoping I'd be able to write to XML from within these separate functions so that I can call them individually when a colour is selected, but I have no idea where everything's meant to go and which bit of code is meant to be in which script.
From the YouTube video linked below, I also have this script, which ties in in some way:
[XmlRoot ("Preferences")]
public class XMLSerialiser {
[XmlArray ("Font"), XmlArrayItem("Colour")]
public Settings[] Settings;
public void Write(string path){
var serialiser = new XmlSerializer(typeof(XMLSerialiser));
using (var stream = new FileStream(path, FileMode.Create)) {
serialiser.Serialize(stream, this);
}
}
public static Settings Read(string path) {
var serialiser = new XmlSerializer(typeof(XMLSerialiser));
using (var stream = new FileStream(path, FileMode.Open)) {
return serialiser.Deserialize(stream) as XMLSerialiser;
}
}
}
What I'd be very grateful for is if someone could either point me in the direction of a good tutorial or explain to me, in very simple terms, how I would go about doing this - what I would have to write, which script I'd have to write it in, and where I'd have to put it in the Unity Editor. I'm very sorry my explanation took up as much space as it did.
Links used:
How to store and retrieve objects using XML?
http://unitynoobs.blogspot.co.uk/2011/02/xml-loading-data-from-xml-file.html
XML Data management in .NET
https://www.youtube.com/watch?v=zAn-ZbJqS90
http://wiki.unity3d.com/index.php?title=Saving_and_Loading_Data%3A_XmlSerializer
http://unitynoobs.blogspot.co.uk/2011/04/xml-writing-to-existing-xml-file.html
Append XML string block to existing XmlDocument
How can I build XML in C#?
Part of what I'm getting confused with is the fact that many of these links seems to use completely different methods to go about it. Take a look at the following two links, for example:
Writing a XML file to iOS with Unity (Using C#)
How to write an XML file in C# in Unity?
Is there a difference between these methods? Is one more preferable than the other?
So I managed to wrap my head around where I wanted things to go, thanks to a few more days of research (and especially this link).
I'm answering my own question so it may help someone else who has the same problem (and because I guess it's a bit silly to leave it unanswered now I have the solution).
To get around the issue of overwriting things, I used the method shown in the link, making an if loop to check whether the file existed. In the first section (the case where the file does not already exist), I used xmlWriter to put things together. XmlWriter appears to be a lot simpler than the method I use in the other section, with the downside that you don't seem to be able to use it without overwriting everything (hence only using it when the file doesn't already exist).
In the case that the file does exist, xDocument is brilliant. I modified the code from the link so that it replaced elements rather than adding new ones (although that can still be done). For this to work, include system.linq and system.xml (possibly system.xml.linq as well). Here is an example:
// Loads the document
XDocument xDocument = XDocument.Load("document.xml");
// Specifies the encoding
new XDeclaration("1.0","utf-8","yes");
// Follows the route settings-font and replaces the current colour
// element with a new one
xDocument.Element("Settings").Element("Font").Element("Colour").ReplaceWith(new XElement("Colour",fontColourHex));
// As above
xDocument.Element("Settings").Element("Background").Element("Colour").ReplaceWith(new XElement("Colour",backgroundColourHex));
// One of the more important things to note is that everything saved in an
// element ought to be a string, and the xml file doesn't like element
// names with spaces in them (use an underscore instead)
xDocument.Element("Settings").Element("Font").Element("Size_Modifier").ReplaceWith(new XElement("Size_Modifier",globalFontSizeModifier.ToString()));
// Saves the document
xDocument.Save("document.xml");
If you're wondering why there is no whitespace between words in this code, it's because, for some reason, Mono doesn't like it. I did find a fix somewhere else for it, but I couldn't get it to work and deleting the whitespace does the job fine.
The resultant file looked like this:
<?xml version="1.0" encoding="utf-8"?>
<Settings>
<Font>
<Colour>FFFFFFFF</Colour>
<Size_Modifier>0</Size_Modifier>
</Font>
<Background>
<Colour>000000FF</Colour>
</Background>
</Settings>
After I modified it and tied it to a couple of functions, all I had to do was create a new game object with the script attached and use it as needed.

XML Seek to specific elements, as efficiently as possible

I'm working on an application where i have to read a specific xml node (the 'progress' node, out of a several large (3meg'ish) files.
I'm doing that via TextReader and XDocument, as shown below
TextReader reader = null;
reader = new StreamReader(Filename);
XDocument objDoc = XDocument.Load(reader);
var progressElement = objDoc.Root.Element("Progress");
var lastAccessTime = progressElement.Element("LastTimeAccessed").Value;
var user = progressElement.Element(("LastUserAccessed").Value;
var lastOpCode = progressElement.Element("LastOpCodeCompleted").Value;
var step = progressElement.Element("StepsCompleted").Value;
XDocument, I believe, is loading the entire file into memory before doing anything else. However, I don't need that! I know the node is going to be the first node in the file.
Is there any type of 'seek' xml parsers that don't cache the entire file first?
Its taking like 15 seconds to parse 10 files for the attributes mentioned above (terrible wireless here).
XmlReader is your best option if all you want is speed. It reads a node at a time, starting at the beginning. The big limitation is that you can't go backward or use any random-access to the XML document.
Yes. You can use a SAX parser, which works differently to XDocument. Basically, a SAX parser works its way through the input XML, firing events back at callback code. (You write these callback handlers.) The main advantages;
The entire document need not be read into a memory model. (A DOM)
You can stop the processing when you have what you want.
Have a look at http://www.ibm.com/developerworks/library/x-tipsaxstop/

Handling strings more than 2 GB

I have an application where an XLS file with lots of data entered by the user is opened and the data in it is converted to XML. I have already mapped the columns in the XLS file to XML Maps. When I try to use the ExportXml method in XMLMaps, I get a string with the proper XML representation of the XLS file. I parse this string a bit and upload it to my server.
The problem is, when my XLS file is really large, the string produced for XML is over 2 GB and I get a Out of Memory exception. I understand that the limit for CLR objects is 2 GB. But in my case I need to handle this scenario. Presently I just message asking the user to send less data.
Any ideas on how I can do this?
EDIT:
This is just a jist of the operation I need to do on the generated XML.
Remove certain fields which are not needed for the server data.
Add something like ID numbers for each row of data.
Modify the values of certain elements.
Do validation on the data.
While the XMLReader stream is a good idea, I cannot perform these operations by that method. While data validation can be done by Excel itself, the other things cannot be done here.
Using XMLTextReader and XMLTextWriter and creating a custom method for each of the step is a solution I had thought of. But to go through the jist above, it requires the XML document to be gone through or processed 4 times. This is just not efficient.
If the XML is that large, then you might be able to use Export to a temporary file, rather than using ExportXML to a string - http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.xmlmap.export.aspx
If you then need to parse/handle the XML in C#, then for handling such large XML structures, you'll probably be better off implementing a custom XMLReader (or XMLWriter) which works at the stream level. See this question for some similar advice - What is the best way to parse large XML (size of 1GB) in C#?
I guess there is no other way then using x64-OS and FX if you really need to hold the whole thing in RAM, but using some other way to process the data like suggested by Stuart may is the better way to go...
What you need to do is to use "stream chaining", i.e. you open up an input stream which reads from your excel file and an output stream that writes to your xml file. Then your conversion class/method will take the two streams as input and read sufficient data from the input stream to be able to write to the output.
Edit: very simple minimal Example
Converting from file:
123
1244125
345345345
4566
11
to
<List>
<ListItem>123</ListItem>
<ListItem>1244125</ListItem>
...
</List>
using
void Convert(Stream fromStream, Stream toStream)
{
using(StreamReader from= new StreamReader(fromStream))
using(StreamWriter to = new StreamWriter(toStream))
{
to.WriteLine("<List>");
while(!from.EndOfStream)
{
string bulk = from.ReadLine(); //in this case, a single line is sufficient
//some code to parse the bulk or clean it up, e.g. remove '\r\n'
to.WriteLine(string.Format("<ListItem>{0}</ListItem>", bulk));
}
to.WriteLine("</List>");
}
}
Convert(File.OpenRead("source.xls"), File.OpenWrite("source.xml"));
Of course you could do this in much more elegent, abstract manner but this is only to show my point

getting element offset from XMLReader

how's everyone doing this morning?
I'm writing a program that will parse a(several) xml files.
This stage of the program is going to be focusing on adding/editing skills/schools/abilities/etc for a tabletop rpg (L5R). What I learn by this one example should carry me through the rest of the program.
So I've got the xml reading set up using XMLReader. The file I'm reading looks like...
<skills>
<skill>
<name>some name</name>
<description>a skill</description>
<type>high</type>
<stat>perception</stat>
<page>42</page>
<availability>all</availability>
</skill>
</skills>
I set up a Skill class, which holds the data, and a SkillEdit class which reads in the data, and will eventually have methods for editing and adding.
I'm currently able to read in everything right, but I had the thought that since description can vary in length, once I write the edit method the best way to ensure no data is overwritten would be to just append the edited skill to the end of the file and wipe out its previous entry.
In order for me to do that, I would need to know where skill's file offset is, and where /skill's file offset is. I can't seem to find any way of getting those offsets though.
Is there a way to do that, or can you guys suggest a better implementation for editing an already existing skill?
If you read your XML into LINQ to XML's XDocument (or XElement), everything could become very easy. You can read, edit, add stuff, etc. to XML files using a simple interface.
e.g.,
var xmlStr = #"<skills>
<skill>
<name>some name</name>
<description>a skill</description>
<type>high</type>
<stat>perception</stat>
<page>42</page>
<availability>all</availability>
</skill>
</skills>
";
var doc = XDocument.Parse(xmlStr);
// find the skill "some name"
var mySkill = doc
.Descendants("skill") // out of all skills
.Where(e => e.Element("name").Value == "some name") // that has the element name "some name"
.SingleOrDefault(); // select it
if (mySkill != null) // if found...
{
var skillType = mySkill.Element("type").Value; // read the type
var skillPage = (int)mySkill.Element("page"); // read the page (as an int)
mySkill.Element("description").Value = "an AWESOME skill"; // change the description
// etc...
}
No need to calculate offsets, manual, step-by-step reading or maintaining other state, it is all taken care of for you.
Don't do it! In general, you can't reliably know anything about physical offsets in the serialized XML because of possible character encoding differences, entity references, embedded comments and a host of other things that can cause the physical and logical layers to have a complex relationship.
If your XML is just sitting on the file system, your safest option is to have a method in your skill class which serializes to XML (you already have one to read XML already), and re-serialize whole objects when you need to.
Tyler,
Umm, sounds like you're suffering from a text-book case of premature optimization... Have you PROVEN that reading and writing the COMPLETE skill list to/from the xml-file is TOO slow? No? Well until it's been proven that there IS NO PERFORMANCE ISSUE, right? So we just write the simplest code that works (i.e. does what we want, without worrying too much about performance), and then move on directly to the next bit of trick functionality... testing as we go.
Iff (which is short for if-and-only-if) I had a PROVEN performance problem then-and-only-then I'd consider writing each skill to individual XML-file, to avert the necessisity for rewriting a potentially large list of skills each time a single skill was modified... But this is "reference data", right? I mean you wouldn't de/serialize your (volatile) game data to/from an XML file, would you? Because an RDBMS is known to be much better at that job, right? So you're NOT going to be rewriting this file often?
Cheers. Keith.

Categories