I'm currently working on a project that involves a lot of XSLT transformations and I really need a debugger (I have XSLTs that are 1000+ lines long and I didn't write them :-).
The project is written in C# and makes use of extension objects:
xslArg.AddExtensionObject("urn:<obj>", new <Obj>());
From my knowledge, in this situation Visual Studio is the only tool that can help me debug the transformations step-by-step. The static debugger is no use because of the extension objects (it throws an error when it reaches elements that reference their namespace). Fortunately, I've found this thread which gave me a starting point (at least I know it can be done).
After searching MSDN, I found the criteria that makes stepping into the transform possible. They are listed here. In short:
the XML and the XSLT must be loaded via a class that has the IXmlLineInfo interface (XmlReader & co.)
the XML resolver used in the XSLTCompiledTransform constructor is file-based (XmlUriResolver should work).
the stylesheet should be on the local machine or on the intranet (?)
From what I can tell, I fit all these criteria, but it still doesn't work. The relevant code samples are posted below:
// [...]
xslTransform = new XslCompiledTransform(true);
xslTransform.Load(XmlReader.Create(new StringReader(contents)), null, new BaseUriXmlResolver(xslLocalPath));
// [...]
// I already had the xml loaded in an xmlDocument
// so I have to convert to an XmlReader
XmlTextReader r = new XmlTextReader(new StringReader(xmlDoc.OuterXml));
XsltArgumentList xslArg = new XsltArgumentList();
xslArg.AddExtensionObject("urn:[...]", new [...]());
xslTransform.Transform(r, xslArg, context.Response.Output);
I really don't get what I'm doing wrong. I've checked the interfaces on both XmlReader objects and they implement the required one. Also, BaseUriXmlResolver inherits from XmlUriResolver and the stylesheet is stored locally. The screenshot below is what I get when stepping into the Transform function. First I can see the stylesheet code after stepping through the parameters (on template-match), I get this:
If anyone has any idea why it doesn't work or has an alternative way of getting it to work I'd be much obliged :).
Thanks,
Alex
I'm not sure about usage of extension objects but as I understand your problem is with debugging of XSLT transformation in code in VS2010.
Here is the function that we use to debug XSLT transformation:
public string ApplyTransformation(string inputFilePath, string xsltFileContent)
{
XslCompiledTransform transform = new XslCompiledTransform(debugEnabled);
File.WriteAllText(xsltTempFilePath,xsltFileContent);
transform.Load(xsltTempFilePath, XsltSettings.TrustedXslt, new XmlUrlResolver());
XmlReader reader = XmlReader.Create(inputFilePath);
StringWriter output = new StringWriter();
XmlWriter writer = XmlWriter.Create(output,transform.OutputSettings);
transform.Transform(reader,writer);
return output.ToString();
}
Unfortunately, there is a bug with VS2010 XSLT debugger which will make your debugging experience worse than in VS2008.
Consider debugging using XML Spy XSLT debugger. It works for me all the time.
Related
I have a batch and want to rebuild this in a .net application. How can I handle this in .net?
-xsl:"style.xsl" resource-path="%runtimepath%%respath%" srcAutotexte="%runtimepath%%respath%\autotext\autotext.xml"
My attempt. How can I include the autotext.xml?
// Create a transformer for the stylesheet.
XsltCompiler compiler = processor.NewXsltCompiler();
compiler.BaseUri = new Uri(styleXslFilePath);
XsltTransformer transformer = compiler.Compile(File.OpenRead(styleXslFilePath)).Load();
The command line options
resource-path="%runtimepath%%respath%"
srcAutotexte="%runtimepath%%respath%\autotext\autotext.xml"
set the values of stylesheet parameters in the transformation.
The equivalent when using the Saxon.Api interface is to call
transformer.SetParameter(
new QName("resource-path"),
new XdmAtomicValue("%runtimepath%%respath%"));
etc.
(Perhaps your shell interprets %xxxx% as a reference to a shell/system variable of some kind - it's a long time since I wrote batch scripts under Windows. If that's the case then you'll need to get hold of the values of these variables. You can do that at the C# level using the .NET API, or you might be able to do it from within XSLT 3.0 using the environment-variable() function.)
I am programming in C#. I was previously using the following command line to convert an xml with a xsl and output it as a html.
java -jar "C:\Data\saxon-he-9.4.0.7.jar" View.xml Stylesheet.xsl -o:output.html
However, I am now trying to use the Saxon .Net API to do the same process using the following code:
var xslt = new FileInfo(#"C:\\Data\\Stylesheet.xsl");
var input = new FileInfo(#"C:\\Data\\View.xml");
var output = new FileInfo(#"C:\\Data\\test.html");
// Compile stylesheet
var processor = new Processor();
var compiler = processor.NewXsltCompiler();
var executable = compiler.Compile(new Uri(xslt.FullName));
// Do transformation to a destination
var destination = new DomDestination();
using (var inputStream = input.OpenRead())
{
var transformer = executable.Load();
transformer.SetInputStream(inputStream, new Uri(input.DirectoryName));
transformer.Run(destination);
}
// Save result to a file (or whatever else you wanna do)
destination.XmlDocument.Save(output.FullName);
However I recieve the error:
"An unhandled exception of type 'Saxon.Api.DynamicError' occurred in saxon9he-api.dll"
When running the line "transformer.Run(destination);"
The following screenshots are from the Visual Studio's Locals Debugging:
$exception {"XSLT 1.0 compatibility mode is not available in this configuration"} Saxon.Api.DynamicError
transformer {Saxon.Api.XsltTransformer} Saxon.Api.XsltTransformer
The first thing you need to do is to get more specific information about the nature of the error. Catching the exception and printing the exception message would be a good start. But Saxon will have written diagnostics to the standard error output, which probably ends up in some log file somewhere, depending on how your application is configured and run. If you can't track it down, try redirecting it as described here: How to capture a Processes STDOUT and STDERR line by line as they occur, during process operation. (C#)
Once you've established the actual error, edit the question and we can start investigating what's wrong if it's not obvious.
A common cause of problems when writing to a DomDestination is that your result tree isn't well-formed, e.g, it has text nodes or multiple elements at the top level. It's not clear why you are writing to a DomDestination - if you just want to produce serialized XML, then write to a Serializer.
LATER
Now you've found the error message ("XSLT 1.0 compatibility mode is not available in this configuration") it should be fairly clear. When a stylesheet specifies version="1.0" and is run with an XSLT 2.0 or 3.0 processor, it runs in a compatibility mode where certain things behave differently (for example xsl:value-of ignores all but the first selected item). This compatibility mode, from Saxon 9.8 onwards, is not available in Saxon-HE. You need to do one of three things: upgrade to Saxon-PE or -EE; revert to an earlier Saxon-HE version; or convert your stylesheet to XSLT 2.0 (which basically means (i) change the value of the version attribute (ii) test that it still works.)
I am using NHibernate mapping-by-code to map the classes.
Sometimes, in order to debug my NHibernate configuration, I would require to check exactly what were the settings passed over to NHibernate, and it is quite difficult do debug the mapping-by-code.
Is there any way where you could convert the generated HbmMapping, back into the Xml file, just as if typed by hand?
This would help a lot in diagnosing if the problem is lying from my mappings!
Option 1
Be warned this will write the XML into your BIN folder causing the IIS pool to recycle, so run once and then comment the WriteAllXmlMapping line back out!
var mapper = new ModelMapper();
mapper.AddMappings(typeof(CmsMeta).Assembly.GetTypes());
//This will write all the XML into the bin/mappings folder
mapper.CompileMappingForEachExplicitlyAddedEntity().WriteAllXmlMapping();
Option 2
This will give you a a single large XML file that you can add a breakpoint to.
var mapper = new ModelMapper();
mapper.AddMappings(typeof(CmsMeta).Assembly.GetTypes());
var mapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
//you could add a breakpoint here!
var mappingXml = mapping.AsString();
The source is from a blog post I wrote a while ago.
My plan:
I'm trying to setup my C# project to communicate with Nodebox to call a certain function which populates a graph and draws it in a new window.
Current situation: [fixed... see Update2]
I have already included all python-modules needed, but im still getting a
Library 'GL' not found
it seems that the pyglet module needs a reference to GL/gl.h, but can't find it due to IronPython behaviour.
Requirement:
The project needs to stay as small as possible without installing new packages. Thats why i have copied all my modules into the project-folder and would like to keep it that or a similar way.
My question:
Is there a certain workaround for my problem or a fix for the library-folder missmatch.
Have read some articles about Tao-Opengl and OpenTK but can't find a good solution.
Update1:
Updated my sourcecode with a small pyglet window-rendering example. Problem is in pyglet and referenced c-Objects. How do i include them in my c# project to be called? No idea so far... experimenting alittle now. Keeping you updated.
SampleCode C#:
ScriptRuntimeSetup setup = Python.CreateRuntimeSetup(null);
ScriptRuntime runtime = new ScriptRuntime(setup);
ScriptEngine engine = Python.GetEngine(runtime);
ScriptSource source = engine.CreateScriptSourceFromFile("test.py");
ScriptScope scope = engine.CreateScope();
source.Execute(scope);
SampleCode Python (test.py):
from nodebox.graphics import *
from nodebox.graphics.physics import Vector, Boid, Flock, Obstacle
flock = Flock(50, x=-50, y=-50, width=700, height=400)
flock.sight(80)
def draw(canvas):
canvas.clear()
flock.update(separation=0.4, cohesion=0.6, alignment=0.1, teleport=True)
for boid in flock:
push()
translate(boid.x, boid.y)
scale(0.5 + boid.depth)
rotate(boid.heading)
arrow(0, 0, 15)
pop()
canvas.size = 600, 300
def main(canvas):
canvas.run(draw)
Update2:
Line 139 [pyglet/lib.py] sys.platform is not win32... there was the error. Fixed it by just using the line:
from pyglet.gl.lib_wgl import link_GL, link_GLU, link_WGL
Now the following Error:
'module' object has no attribute '_getframe'
Kind of a pain to fix it. Updating with results...
Update3:
Fixed by adding following line right after first line in C#-Code:
setup.Options["Frames"] = true;
Current Problem:
No module named unicodedata, but in Python26/DLLs is only a *.pyd file`. So.. how do i implement it now?!
Update4:
Fixed by surfing: link text and adding unicodedata.py and '.pyd to C# Projectfolder.
Current Problem:
'libGL.so not found'... guys.. im almost giving up on nodebox for C#.. to be continued
Update5:
i gave up :/ workaround: c# communicating with nodebox over xml and filesystemwatchers. Not optimal, but case solved.
-X:Frames enables the frames option as runtime (it slows code down a little to have access to the Python frames all the time).
To enable frames when hosting you just need to do:
ScriptRuntimeSetup setup = Python.CreateRuntimeSetup(new Dictionary<string, object>() {
{ "Frames", true }
});
Instead of the null that you're passing now. That's just creating a new dictionary for the options dictionary w/ the contents "Frames" set to true. You can set other options in there as well and in general the -X:Name option is the same here as it is for the command line.
I am using WorkflowMarkupSerializer to save a statemachine workflow - it saves the states OK, but does not keep their positions. The code to write the workflow is here:
using (XmlWriter xmlWriter = XmlWriter.Create(fileName))
{
WorkflowMarkupSerializer markupSerializer
= new WorkflowMarkupSerializer();
markupSerializer.Serialize(xmlWriter, workflow);
}
The code to read the workflow is:
DesignerSerializationManager dsm
= new DesignerSerializationManager();
using (dsm.CreateSession())
{
using (XmlReader xmlReader
= XmlReader.Create(fileName))
{
//deserialize the workflow from the XmlReader
WorkflowMarkupSerializer markupSerializer
= new WorkflowMarkupSerializer();
workflow = markupSerializer.Deserialize(
dsm, xmlReader) as Activity;
if (dsm.Errors.Count > 0)
{
WorkflowMarkupSerializationException error
= dsm.Errors[0]
as WorkflowMarkupSerializationException;
throw error;
}
}
}
Open Control Panel -> "Regional and language options" and set list separator to ',' (comma)
and workflow serializer will use ',' (comma) as separator for X,Y coordinates for struct SizeF
then select ';' and workflow serializer will use ';' (semicolon) as separator.
This really stupid that serializer use regional setting for serialize markup.
The position of all the states is kept in a separate file. You'll need to drag it around with the markup of the workflow itself. Luckily, it's just XML as well, so you might be able to reuse most of the code you have up there. If memory serves, I believe it's simply NameOfYourWorkflow.layout.
I agree with x0n - the designer is really bad in Visual Studio.
OK, this tutorial gives good information on how to do it - although so far I am only able to save the layout, I haven't been able to correctly use the layout. The information in question is about 2/3rds down (or just do a search for .layout)
(How does one close his own question?)
Note that there is a bug in either the serialize or deserialize of the XML created (named in the example with an extension of .layout.)
It produces the following xml as the first line of the file:
<?xml version="1.0" encoding="utf-8"?><StateMachineWorkflowDesigner xmlns:ns0="clr-namespace:System.Drawing;Assembly=System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Name="New" Location="30, 30" Size="519, 587" AutoSizeMargin="16, 24" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
When reading this back in, the size attribute causes an exception. I removed Size="519, 587" from the file and the workflow is loaded back correctly. Right now, I write the file, open it and remove the size, then close it. I need to think about a more elegant solution, but at least I am now saving and restoring a state machine workflow.
Hah, even the workflow designer hosted in Visual Studio 2008 loses the positions of states randomly. This tells me it's probably not an easy task, and is information external to the Activities that comprise it. I'd dig more around the host for information; if I find something, I'll post back.