Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Fengelz 106 posts 221 karma points
    Jul 28, 2009 @ 14:08
    Fengelz
    0

    XsltSearch: Error reading XSLT file

    Hi

    I recently uploaded an Umbraco project to a remote server. I installed the XsltSearch package which worked out perfect on my local machine.

    We had some issues with the provider and getting Umbraco to run on full trust, but it all worked out after a while.

    Now the only single thing that doesnt work on the server is the XsltSearch.

    All I get on the search.aspx page is:

    Error reading XSLT file: \xslt\XSLTsearch.xslt

    I have other xslt files in the solution that appears to wotk fine.

    Anybody who had similar experience, who know what causes this?

    best regards

    Sune Fengel

     

  • Douglas Robar 3570 posts 4711 karma points MVP ∞ admin c-trib
    Jul 28, 2009 @ 14:26
    Douglas Robar
    2

    I would guess this is a file permission issue. Check that the owner of the site's application pool has at least modify permission to the /xslt/xsltsearch.xslt file (and the entire /xslt folder for that matter). That should resolve it.

    But if not, try viewing the search.aspx page with debugging information shown as well. http://example.com/search.aspx?umbDebugShowTrace=true (change the domain and path to the search page as appropriate for your site). Scroll down and you should see some red text and a more complete description of the problem. That should help pinpoint the issue.

    cheers,
    doug.

  • Fengelz 106 posts 221 karma points
    Jul 28, 2009 @ 16:08
    Fengelz
    0

    Great! Thanks for the help.

    I found the error in the debug trace.

    it says 

     

     

    Error loading XSLT XSLTsearch.xslt
    Could not load file or assembly 'file:///C:\WINDOWS\TEMP\k8ur_9_j.dll' or one of its dependencies. Access is denied.
      at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)

    The name of the dll changes when I refresh the page.

    The host provider had no idea what the message could mean.

    Is it a dll that is generated from the XsltSearch Package?

    best regards 

    Sune Fengel

  • Douglas Robar 3570 posts 4711 karma points MVP ∞ admin c-trib
    Jul 28, 2009 @ 16:18
    Douglas Robar
    0

    It isn't related to XSLTsearch specifically because it has only 1 file, the /xslt/xsltsearch.xslt file.

    But there's definitely a file permission problem with something being loaded. I would guess it is a dll in the /bin folder since reflection is being called. It seems there's a need to write a temporary file that isn't allowed by the host. Any chance the host would allow CRUD permissions to the temp folder, at least temporarily to see if that resolves the issue?

    cheers,
    doug.

  • Fengelz 106 posts 221 karma points
    Jul 28, 2009 @ 16:28
    Fengelz
    0

    Thanks for the swift replies.

    I didnt think it was the xslt search, but I thougt I'd ask just in case.

    I'll ask the host provider if they'll allow CRUD permissions on the temp folder.

    best regards 

    Sune Fengel

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    Jul 28, 2009 @ 18:42
    Morten Bock
    2

    As Doug says, it's a problem with permissions.

    What happens is that because the XSLT search contains some inline C# code, the XSLT parser will dynamically compile a dll assembly in order to run the code. This is just the way .Net works in this respect. This assembly will be written to the /temp folder because it is just that, temporary.

    I hope this explains a bit about why you need the permissions, and maybe your host knows a workaround for this sort of requirement.

  • Douglas Robar 3570 posts 4711 karma points MVP ∞ admin c-trib
    Jul 28, 2009 @ 20:04
    Douglas Robar
    0

    Wow, I learn something new every day. Thanks, Morten!!

    cheers,
    doug.

  • Lee 3 posts 33 karma points
    Aug 19, 2009 @ 13:04
    Lee
    0

    Hi Everyone,

    I am having what I think is possibly the same problem, could you tell me where the temp folder should be located so I can the permssions?

    Many thanks

    Lee

  • BarneyHall 141 posts 210 karma points
    Aug 19, 2009 @ 13:54
    BarneyHall
    0

    Hello Lee. I had to set permissions on the "C:/windows/temp" folder to resolve this problem.

    Barney

    See my post: http://our.umbraco.org/forum/getting-started/questions-about-runway-and-modules/3511-Problem-with-CWS2-search---suspect-permissions---anyone-help

     

  • Dave Rollins 35 posts 48 karma points
    Aug 22, 2009 @ 18:56
    Dave Rollins
    0

    Doug - in a hosted environment c:\windows\temp typically is not something the ISP wants you to write to

    Have you thought of peeling all your embedded C# code out of the xlst and into app_code as a class then referencing this code from the xslt - when accessed it would auto-compile itself into the bin folder which ISPs more frequently give you a way to grant full acess to.

    Something to think about anyways.

  • Chris Koiak 700 posts 2626 karma points
    Aug 22, 2009 @ 20:12
    Chris Koiak
    0

    I didn't know that either.

    Doug -  Although it's great having XsltSearch in a single file, maybe you could provide a version that ran it's c# code via xslt extensions?

  • Dave Rollins 35 posts 48 karma points
    Aug 23, 2009 @ 16:22
    Dave Rollins
    1

    I successfully pulled the c# code out of the xslt for this search to solve this problem by creating a custom xslt extension class.

    This was very easy to do :)

    The problem with compiling to temp in a hosted environment is no longer an issue once you do this.

    Steps required to do this:

    1. Create a dll to house a class you will be referencing from the XSLTSearch xslt file and add this dll you bin folder - call it PSXSLTSearch.dll
    2. Modify the config/xsltextensions.config file
    3. Modify the XSLTSearch.xslt file - link to your new extension, remove the embedded C# code

    Step 1 - Here's the class file I created -  

    using

     

    System;

    using

     

    System.Text;

    namespace

     

    PercipientStudios

    {

     

    /// <summary>

     

    /// XSLTSearch support class

     

    /// </summary>

     

    public class XSLTSearchUtil

    {

     

    public static double power(double x, double y)

    {

     

    return Math.Pow(x, y);

    }

     

    public static string uppercase(string s)

    {

     

    return s.ToUpper();

    }

     

    public static string escapeSearchTerms(string data)

    {

     

    return data.Replace(Convert.ToString((char)38), "&amp;");

    }

     

    public static string unescapeSearchTerms(string data)

    {

     

    return data.Replace("&amp;", Convert.ToString((char)38));

    }

     

    public static double hitCount(string data, string find)

    {

     

    if (data == null || data == "" || find == null || find == "")

     

    return 0;

     

    string after = data.ToLower().Replace(find.ToLower(), "");

     

    return (data.Length - after.Length) / find.Length;

    }

     

    public static int indexOfMany(string search, string[] find)

    {

     

    int foundIndex = search.Length;

     

    foreach (string toFind in find)

    foundIndex =

    Math.Min(foundIndex, search.ToUpper().IndexOf(toFind.ToUpper()));

     

    return foundIndex;

    }

     

    public static string contextOfFind(string data, string find, int wordsBefore, int wordsAfter, int maxChars)

    {

     

    // NOTE: This only makes sense if the searchFields and previewFields are identical.

     

    // Otherwise, you can find a match but not see its context.

     

    try

    {

     

    if (data.Length == 0)

     

    return "";

     

    string findList = getFirstElement(find, " ");

    find = removeFirstElement(find,

    " ");

     

    while (find != "")

    {

    findList +=

    "|" + getFirstElement(find, " ").ToUpper();

    find = removeFirstElement(find,

    " ");

    }

     

    string[] findPhrases = findList.Split('|');

     

    string remaining = data;

     

    string output = "";

     

    int loop = 0;

     

    string[] after = new string[0];

     

    while (output.Length < maxChars && remaining != "")

    {

     

    int findIndex = indexOfMany(remaining, findPhrases);

     

    if (findIndex == -1)

     

    break;

    findIndex = remaining.IndexOf(

    " ", findIndex);

     

    if (findIndex == -1)

    {

    output += remaining;

     

    break;

    }

     

    string[] before = remaining.Substring(0, findIndex).Split(' ');

     

    if (before.Length > wordsBefore)

    output +=

    " ... ";

    output +=

    String.Join(" ", before, Math.Max(0, before.Length - wordsBefore), Math.Min(before.Length, wordsBefore));

    remaining = remaining.Substring(findIndex);

    after = remaining.Split(

    ' ');

     

    string afterText = String.Join(" ", after, 0, Math.Min(after.Length, wordsAfter));

     

    int nextFindIndex = indexOfMany(afterText, findPhrases);

     

    if (nextFindIndex > -1)

    nextFindIndex = afterText.IndexOf(

    " ", nextFindIndex);

     

    while (nextFindIndex > -1)

    {

    output += afterText.Substring(0, nextFindIndex);

    remaining = remaining.Substring(nextFindIndex);

    after = remaining.Split(

    ' ');

    afterText =

    String.Join(" ", after, 0, Math.Min(after.Length, wordsAfter));

    nextFindIndex = indexOfMany(afterText, findPhrases);

     

    if (nextFindIndex > -1)

    nextFindIndex = afterText.IndexOf(

    " ", nextFindIndex);

    }

    output += afterText;

    remaining = remaining.Substring(afterText.Length);

    }

    maxChars = (after.Length > wordsAfter) ? maxChars - 3 : maxChars;

    output = output.Trim();

     

    while (output.Length > maxChars)

    output = output.Substring(0, output.LastIndexOf(

    " "));

     

    if (after.Length > wordsAfter)

    output +=

    " ...";

     

    return output;

    }

     

    catch

    {

     

    return "";

    }

    }

     

    public static string surround(string data, string find, string before, string after)

    {

     

    // searches for find within data, then surrounds it with before and after tags

     

    // note: replace with the actual text found, to preserve the case

     

    string nextWord = getFirstElement(find, " ");

     

    string remainingWords = find;

     

    while (nextWord != "")

    {

     

    int index = data.ToLower().IndexOf(nextWord.ToLower());

     

    while (index > -1)

    {

     

    string replacement = before + data.Substring(index, nextWord.Length) + after;

    data = data.Substring(0, index) + replacement + data.Substring(index + nextWord.Length);

    index = data.ToLower().IndexOf(nextWord.ToLower(), index + replacement.Length);

    }

    remainingWords = removeFirstElement(remainingWords,

    " ");

    nextWord = getFirstElement(remainingWords,

    " ");

    }

     

    return data;

    }

     

    public static long getTime()

    {

     

    // get current time

     

    return DateTime.Now.Ticks;

    }

     

    public static double getTimeSpan(long startTime, long stopTime)

    {

     

    // return time span in milliseconds

     

    return TimeSpan.FromTicks(stopTime - startTime).TotalMilliseconds;

    }

     

    public static string getFirstElement(string delimitedList, string delimiter)

    {

     

    // strip all leading delimiters

     

    while (delimitedList.IndexOf(delimiter) == 0)

    delimitedList = delimitedList.Remove(0, delimiter.Length).Trim();

     

    if (delimitedList.Length == 0)

     

    return "";

     

    // searching on a phrase

     

    if (delimiter == " " && delimitedList.Substring(0, 1) == "'" && delimitedList.IndexOf("'", 1) > -1)

     

    return delimitedList.Substring(1, delimitedList.IndexOf("'", 1) - 1);

     

    if (delimiter == " " && delimitedList.Substring(0, 1) == "\"" && delimitedList.IndexOf("\"", 1) > -1)

     

    return delimitedList.Substring(1, delimitedList.IndexOf("\"", 1) - 1);

     

    // only one element

     

    if (delimitedList.IndexOf(delimiter) == -1)

     

    return delimitedList.Trim();

     

    // return first element

     

    return delimitedList.Split(delimiter.ToCharArray()[0])[0].Trim();

    }

     

    public static string removeFirstElement(string delimitedList, string delimiter)

    {

     

    string firstElement = getFirstElement(delimitedList, delimiter);

     

    // handle phrase delimiters

     

    if (delimiter == " " && delimitedList.Substring(0, 1) == "'" && delimitedList.IndexOf("'", 1) > -1)

     

    return delimitedList.Remove(0, firstElement.Length + 2).Trim();

     

    if (delimiter == " " && delimitedList.Substring(0, 1) == "\"" && delimitedList.IndexOf("\"", 1) > -1)

     

    return delimitedList.Remove(0, firstElement.Length + 2).Trim();

     

    while (delimitedList.IndexOf(delimiter) == 0)

    delimitedList = delimitedList.Remove(0, delimiter.Length).Trim();

     

    return delimitedList.Remove(0, firstElement.Length).Trim();

    }

     

    public static string getParameter(string value, string defaultValue)

    {

     

    if (value == "")

     

    return defaultValue;

     

    else

     

    return value.Replace(" ", "");

    }

     

    public static string getListParameter(string value, string defaultValue)

    {

     

    // remove all spaces

    value = value.Replace(

    " ", "");

    defaultValue = defaultValue.Replace(

    " ", "");

     

    if (value == "")

     

    return "," + defaultValue + ",";

     

    else

     

    return "," + value + ",";

    }

    }

    }

     

    Step 2 - I modified my xlstextensions.config file like this

    <?

     

    xml version="1.0" encoding="utf-8" ?>

    <

     

    XsltExtensions>

    <

     

    ext assembly="/bin/PSXSLTSearch" type="PercipientStudios.XSLTSearchUtil" alias="ps" />

    </

     

    XsltExtensions>

    Step 3 - and finally I changed up the transform line on my XSLTSearch style like this

    <

     

    xsl:stylesheet version="1.0"

     

     

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

     

     

    xmlns:msxml="urn:schemas-microsoft-com:xslt"

     

     

    xmlns:msxsl="urn:schemas-microsoft-com:xslt"

     

     

    xmlns:umbraco.library="urn:umbraco.library"

     

     

    xmlns:ps="urn:ps"

     

     

    exclude-result-prefixes="msxml umbraco.library ps">

    And... I got rid of the CDATA section of C# code at the bottom

    That's it.

    Works like a charm.

  • Fengelz 106 posts 221 karma points
    Aug 24, 2009 @ 10:09
    Fengelz
    0

    Beautiful!

    Got it to work by extracting it to a dll.

    thanks a lot 

    - Sune

  • Bo Petersen 28 posts 61 karma points
    Feb 03, 2010 @ 21:54
    Bo Petersen
    0

    It is absolutely possible to build a DLL with the c# code implemented directly in the xsltsearch.xslt file.

    1. Add a new web project in visual studio.
    2. Add new Project to the solution being a "Windows Class Library"
    3. Make a namespace in the class library called 'PercipientStudios' to keep Kudos to Douglas Robar
    4. Add a Class called XsltSearch like this with all the methods in it as public static methods like the code below in pt. 8....
    5. Build your solution, copy the dll file from the project bin folder and paste it to your websites bin folder
    6. Add corresponding XslExtensions in XslExtensions.config in the config folder of Umbraco mine looks like this

        <ext assembly="/bin/PercipientStudios" type="PercipientStudio.XsltSearch" alias="ps" />

    7. Remove the inline C# code from XSLTsearch.xslt and replace xml doctype and stylesheet content in the top of the xslt file with this little snippet.

      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE xsl:stylesheet [
          <!ENTITY nbsp "&#x00A0;">
      ]>
      <xsl:stylesheet version="1.0"
          xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
          xmlns:umbraco.library="urn:umbraco.library"
          xmlns:ps ="urn:ps"
          exclude-result-prefixes="umbraco.library ps">

      --------------------------------------------------
    8. Code to put in your library

      using System;

      namespace PercipientStudios
      {
          public class XsltSearch
          {
              public static double power(double x, double y)
              {
                  return Math.Pow(x, y);
              }

              public static string uppercase(string s)
              {
                  return s.ToUpper();
              }

              public static string escapeSearchTerms(string data)
              {
                  return data.Replace(Convert.ToString((char)38), "&amp;");
              }

              public static string unescapeSearchTerms(string data)
              {
                  return data.Replace("&amp;", Convert.ToString((char)38));
              }

              public static double hitCount(string data, string find)
              {
                  if (data == null || data == "" || find == null || find == "")
                      return 0;

                  string after = data.ToLower().Replace(find.ToLower(), "");
                  return (data.Length - after.Length) / find.Length;
              }

              public static int indexOfMany(string search, string[] find)
              {
                  int foundIndex = search.Length;
                  foreach (string toFind in find)
                      foundIndex = Math.Min(foundIndex, search.ToUpper().IndexOf(toFind.ToUpper()));
                  return foundIndex;
              }

              public static string contextOfFind(string data, string find, int wordsBefore, int wordsAfter, int maxChars)
              {
                  // NOTE: This only makes sense if the searchFields and previewFields are identical.
                  // Otherwise, you can find a match but not see its context.

                  try
                  {
                      if (data.Length == 0)
                          return "";

                      string findList = getFirstElement(find, " ");
                      find = removeFirstElement(find, " ");
                      while (find != "")
                      {
                          findList += "|" + getFirstElement(find, " ").ToUpper();
                          find = removeFirstElement(find, " ");
                      }
                      string[] findPhrases = findList.Split('|');

                      string remaining = data;
                      string output = "";
                      string[] after = new string[0];

                      while (output.Length < maxChars && remaining != "")
                      {
                          int findIndex = indexOfMany(remaining, findPhrases);
                          if (findIndex == -1)
                              break;
                          findIndex = remaining.IndexOf(" ", findIndex);

                          if (findIndex == -1)
                          {
                              output += remaining;
                              break;
                          }

                          string[] before = remaining.Substring(0, findIndex).Split(' ');
                          if (before.Length > wordsBefore)
                              output += " ... ";

                          output += String.Join(" ", before, Math.Max(0, before.Length - wordsBefore), Math.Min(before.Length, wordsBefore));
                          remaining = remaining.Substring(findIndex);
                          after = remaining.Split(' ');
                          string afterText = String.Join(" ", after, 0, Math.Min(after.Length, wordsAfter));
                          int nextFindIndex = indexOfMany(afterText, findPhrases);
                          if (nextFindIndex > -1)
                              nextFindIndex = afterText.IndexOf(" ", nextFindIndex);

                          while (nextFindIndex > -1)
                          {
                              output += afterText.Substring(0, nextFindIndex);
                              remaining = remaining.Substring(nextFindIndex);
                              after = remaining.Split(' ');
                              afterText = String.Join(" ", after, 0, Math.Min(after.Length, wordsAfter));
                              nextFindIndex = indexOfMany(afterText, findPhrases);
                              if (nextFindIndex > -1)
                                  nextFindIndex = afterText.IndexOf(" ", nextFindIndex);
                          }

                          output += afterText;
                          remaining = remaining.Substring(afterText.Length);

                      }

                      maxChars = (after.Length > wordsAfter) ? maxChars - 3 : maxChars;
                      output = output.Trim();

                      while (output.Length > maxChars)
                          output = output.Substring(0, output.LastIndexOf(" "));

                      if (after.Length > wordsAfter)
                          output += " ...";

                      return output;
                  }

                  catch
                  {
                      return "";
                  }

              }

              public static string surround(string data, string find, string before, string after)
              {
                  // searches for find within data, then surrounds it with before and after tags
                  // note: replace with the actual text found, to preserve the case

                  string nextWord = getFirstElement(find, " ");
                  string remainingWords = find;
                  while (nextWord != "")
                  {
                      int index = data.ToLower().IndexOf(nextWord.ToLower());
                      while (index > -1)
                      {
                          string replacement = before + data.Substring(index, nextWord.Length) + after;
                          data = data.Substring(0, index) + replacement + data.Substring(index + nextWord.Length);
                          index = data.ToLower().IndexOf(nextWord.ToLower(), index + replacement.Length);
                      }
                      remainingWords = removeFirstElement(remainingWords, " ");
                      nextWord = getFirstElement(remainingWords, " ");
                  }
                  return data;
              }

              public static long getTime()
              {
                  // get current time
                  return DateTime.Now.Ticks;
              }

              public static double getTimeSpan(long startTime, long stopTime)
              {
                  // return time span in milliseconds
                  return TimeSpan.FromTicks(stopTime - startTime).TotalMilliseconds;
              }

              public static string getFirstElement(string delimitedList, string delimiter)
              {
                  // strip all leading delimiters
                  while (delimitedList.IndexOf(delimiter) == 0)
                      delimitedList = delimitedList.Remove(0, delimiter.Length).Trim();

                  if (delimitedList.Length == 0)
                      return "";

                  // searching on a phrase
                  if (delimiter == " " && delimitedList.Substring(0, 1) == "'" && delimitedList.IndexOf("'", 1) > -1)
                      return delimitedList.Substring(1, delimitedList.IndexOf("'", 1) - 1);

                  if (delimiter == " " && delimitedList.Substring(0, 1) == "\"" && delimitedList.IndexOf("\"", 1) > -1)
                      return delimitedList.Substring(1, delimitedList.IndexOf("\"", 1) - 1);

                  // only one element
                  if (delimitedList.IndexOf(delimiter) == -1)
                      return delimitedList.Trim();

                  // return first element
                  return delimitedList.Split(delimiter.ToCharArray()[0])[0].Trim();
              }

              public static string removeFirstElement(string delimitedList, string delimiter)
              {
                  string firstElement = getFirstElement(delimitedList, delimiter);

                  // handle phrase delimiters
                  if (delimiter == " " && delimitedList.Substring(0, 1) == "'" && delimitedList.IndexOf("'", 1) > -1)
                      return delimitedList.Remove(0, firstElement.Length + 2).Trim();

                  if (delimiter == " " && delimitedList.Substring(0, 1) == "\"" && delimitedList.IndexOf("\"", 1) > -1)
                      return delimitedList.Remove(0, firstElement.Length + 2).Trim();

                  while (delimitedList.IndexOf(delimiter) == 0)
                      delimitedList = delimitedList.Remove(0, delimiter.Length).Trim();

                  return delimitedList.Remove(0, firstElement.Length).Trim();
              }

              public static string getParameter(string value, string defaultValue)
              {
                  if (value == "")
                      return defaultValue;
                  return value.Replace(" ", "");
              }

              public static string getListParameter(string value, string defaultValue)
              {
                  // remove all spaces
                  value = value.Replace(" ", "");
                  defaultValue = defaultValue.Replace(" ", "");

                  if (value == "")
                      return "," + defaultValue + ",";
                  return "," + value + ",";
              }
          }
      }

     

     

    Hopes this gives you a kick in the right direction - this has been tested for umbracoo 4.0.3, but i imagine it would work for previous versions as well. I have not published this as a package as it would violate some licence in this crazy world, but i works.

    <Bo /> - www.boblog.dk - not running yet though.

     

  • Douglas Robar 3570 posts 4711 karma points MVP ∞ admin c-trib
    Feb 04, 2010 @ 12:45
    Douglas Robar
    1

    XSLTsearch is getting an update for umbraco 4.1 and medium trust... the inline c# code will be put into an xslt extension in the app_code folder. That will make two files but both will be available for easy editing. App_code xslt extensions are an umbraco 4.1 feature to support medium trust. This is the solution that's coming.

    Until then, setting

    <add key="umbracoDebugMode" value="false" />

    should resolve (at least most) of the problems.

    You can read more about the reason for this in the comments of my blog post, http://blog.percipientstudios.com/2009/9/21/advanced-xslt-with-net-namespaces.aspx

    cheers,
    doug.

     

  • Steven Wilber 103 posts 98 karma points
    Feb 12, 2010 @ 13:17
    Steven Wilber
    0

    Hi Guys,

    Doug actually answered this problem very nicely in his comments on his blog.

    http://blog.percipientstudios.com/2009/9/21/advanced-xslt-with-net-namespaces.aspx

    It seems that by setting: umbracoDebugMode = false in the web.config it should solve most of the problems.

    It did for me anyway. Cheers Mr Robar.

    Steve

  • Douglas Robar 3570 posts 4711 karma points MVP ∞ admin c-trib
    Feb 14, 2010 @ 16:51
    Douglas Robar
    0

    You're very welcome, Steve!

    Setting umbracoDebugMode=false in the web.config should resolve the issue in most cases with umbraco 4.0.3 or earlier. In umbraco 4.1 I'll update XSLTsearch to put the c# code into an app_code xslt extension, which will definitely resolve the issue going forward.

    cheers,
    doug.

Please Sign in or register to post replies

Write your reply to:

Draft