2

I have a load of XSLT from a third party which i need to use to transform some data.

If I use xsltproc it works fine and outputs data as expected.

I have the following C# code to try and use it in-process:

sXML is the lump of XML oJob.ContentTemplate is the local file path to the XSLT file

try
{
    using (StringWriter oOutputString = new StringWriter())
    {
        using (XmlTextWriter oOutputWriter = new XmlTextWriter(oOutputString))
        {
            using (StringReader oInputString = new StringReader(sXML))
            {
                using (XmlTextReader oInputReader = new XmlTextReader(oInputString))
                {
                    XslCompiledTransform oXSLTTransform = new XslCompiledTransform();
                    oXSLTTransform.Load(oJob.ContentTemplate, XsltSettings.TrustedXslt, new XmlUrlResolver());
                    oXSLTTransform.Transform(oInputReader, oOutputWriter);
                    String sHTML = oOutputWriter.ToString();
                }
            }
        }
    }
}
catch (Exception e)
{}

The exception thrown is:

Additional information: Cannot find the script or external object that implements prefix 'http://dlxs.org'.

The XSLT is fairly complicated and I don't understand most of it currently. Is there a way I can get this working without delving too far into the XSLT?

Visual Studio 2010 should support EXSLT right?

Edit : If i enable debug and step into it I can see the error on the line:

<xsl:import href="../../lib/xslfunctions.xsl"/>
......
<xsl:when test="contains($BibRegions, dlxs:normAttr($searchRgn))">

These functions should be included already, one of the local XSLT files contains this:

 <?xml version="1.0" encoding="UTF-8" ?>
 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:str="http://exslt.org/strings" xmlns:exsl="http://exslt.org/common" xmlns:func="http://exslt.org/functions" xmlns:dlxs="http://dlxs.org" extension-element-prefixes="str exsl dlxs func" exclude-result-prefixes="str exsl dlxs func">
<!-- extension functions -->
<func:function name="dlxs:normAttr">
    <xsl:param name="attr"/>
    <!-- strip out spaces,commas,question marks -->
    <xsl:variable name="temp" select="translate($attr,' ,?','')"/>
    <func:result select="translate($temp,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')"/>
</func:function>
.....
</xsl:stylesheet>

Is it that Visual Studio can't open these files because they use UNIX paths or because it can't open the local files due to security issues?

Edit 2 :

The extensions that I'm using are:

 <xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:str="http://exslt.org/strings"
  xmlns:exsl="http://exslt.org/common"
  xmlns:func="http://exslt.org/functions"
  xmlns:dlxs="http://dlxs.org"
  extension-element-prefixes="str exsl dlxs func"
  exclude-result-prefixes="str exsl dlxs func">

I'm very much an XSLT beginner so aren't sure what you need.

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
Gordon Thompson
  • 4,764
  • 8
  • 48
  • 62
  • 1
    Seems you are using some XSLT extensions. You need to correctly specify where to find them. How this is done depends on the extensions that you use. Could you please post some more details? – Dirk Vollmar Feb 14 '11 at 21:39

3 Answers3

2

Only the EXSLT Common module is supported by the .NET XSLT engine. To use all of EXSLT, you must use one of the compatible engines listed here (or rewrite your stylesheets):

EXSLT - func:function

EDIT: You might get lucky using the Mvp.Xml library developed by some Microsoft MVPs which is available at Codeplex. It offers some EXSLT support:

Mvp.Xml Project

Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
  • that's a shame, none of those seem to be available for .NET. – Gordon Thompson Feb 14 '11 at 21:49
  • thanks but i don't think mvp.xml helps. I've tried my code with these libraries but i still have the same error. – Gordon Thompson Feb 15 '11 at 09:46
  • 1
    @Gordon Carpenter-Thompson: If you are bound to .NET you might want to have a look at the (commercial) version of SAXON which brings support for EXSLT on .NET too. I haven't tried it myself though. – Dirk Vollmar Feb 15 '11 at 09:51
  • 1
    @Gordon Carpenter-Thompson: Explanation of error message: because `func:function` is a top level element in not null namespace and .Net doesn't implement the `http://exslt.org/functions` module of EXSLT, this element is going to be ignored by the processor. Then, `dlxs:normAttr()` extension function invocation rise an error because the implementation isn't found. Stylesheet functions definitions is not the standard XSLT 1.0 mechanism. You should consider to upgrade to XSLT 2.0 for this feature. –  Feb 15 '11 at 21:51
  • "EXSLT is not supported by the .NET XSLT engine." - This is wrong, or if I'm being charitable, imprecise. XslCompiledTransform supports at least part of EXSL - I know that because I'm using it. It seems not to support the strings module however. – Tom W Nov 29 '12 at 08:34
  • @TomW: I updated the answer. Still (native) support is very basic if you consider the rather large feature set provided by the available EXSLT modules (unless I'm missing something). – Dirk Vollmar Nov 29 '12 at 12:22
1

You need to look at your XSLT document for the namespace http://dlxs.org. I would go out to the website here:

http://www.dlxs.org/products/index.html

Looks like your XSLT is using some extensions that are needed.

1

Thanks for all of the help.

I couldn't get this working using any of the native .NET libraries so worked around it. The program that this is used in is only ever intended to be run once to populate a database so performance isn't incredibly important. For those of you who are interested here is my solution. I use XSLTProc.exe to transform the data, streaming out to disk in a temporary file and then read the output back in again. Nasty but works.

using (TemporaryFile oTempInputFile = new TemporaryFile())
{
    //write the content out to the temporary file
    using (StreamWriter oWriter = new StreamWriter(oTempInputFile.FilePath, false, System.Text.Encoding.UTF8))
    {
        oWriter.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
        oWriter.WriteLine(oTextNode.OuterXml);
        oWriter.Close();
    }


    using (TemporaryFile oTempOutputFile = new TemporaryFile())
    {
        try
        {
            String sXSLTProcArguments = "-o \"" + oTempOutputFile.FilePath + "\" \"" + oJob.ContentTemplate + "\" \"" + oTempInputFile.FilePath + "\"";

            Process oProcess = new Process();
            oProcess.StartInfo.UseShellExecute = false;
            oProcess.StartInfo.FileName = oJob.XSLTParser;
            oProcess.StartInfo.Arguments = sXSLTProcArguments;
            oProcess.StartInfo.RedirectStandardOutput = true;
            oProcess.StartInfo.RedirectStandardError = true;
            oProcess.StartInfo.CreateNoWindow = true;
            oProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
            oProcess.Start();
            oProcess.WaitForExit(5000);

            if (File.Exists(oTempOutputFile.FilePath))
            {
                using (StreamReader oReader = new StreamReader(oTempOutputFile.FilePath))
                {
                    String sHTML = oReader.ReadToEnd();

                    if (sHTML.Length == 0)
                    {
                        Logger.Write(new DebugLogEntry("No HTML content was generated"));
                    }
                    else
                    {
                        //Do something with sHTML
                    }
                }
            }
            else
            {
                Logger.Write(new GeneralLogEntry("Failed to transform content for " + sDocumentID));
            }
        }
        catch (Exception e)
        {
            Logger.Write(new GeneralLogEntry("Exception thrown when transforming content for " + sDocumentID));
            Logger.Write(new DebugLogEntry(e.Message));
            Logger.Write(new DebugLogEntry(e.StackTrace));
        }
    }
}    
Gordon Thompson
  • 4,764
  • 8
  • 48
  • 62