Copied to clipboard

Flag this post as spam?

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


  • Daniel Lindstrom 454 posts 271 karma points
    Jan 29, 2009 @ 09:57
    Daniel Lindstrom
    0

    how to send nodeset to xslt extension, and back?

    Hello

    How do I send a nodeset ('$currentPage/node') to an xslt extension as a parameter?

    What datatype as inparameter in Csharp? XPathNodeIterator?

    I want to manipulate the xml in the extension by adding external data and then send it back as an XPathNodeIterator to the xslt macro so that I can access and sort on the external data in the xslt.

    Any suggestions, examples or experiences of something like this to share?

    I found an example on how to send xml back to the xslt macro here:
    http://blockquote.be/examples/umbraco-xslt-lib-astuanax.txt

    I'll make sure to post back any findings I do myself.

    I'm running v3.0.6 if that matters.

  • Daniel Lindstrom 454 posts 271 karma points
    Jan 29, 2009 @ 12:34
    Daniel Lindstrom
    0

    Whatever I try, the nodeset I send to csharp (inline or extension) gets stripped of its xml tags.
    I've tried inparameters String and XMLPathNodeIterator.

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    Jan 30, 2009 @ 00:32
    Morten Bock
    0

    I have not tried sending the actual nodeset to an extension, but you could try to rethink it a bit.

    If you pass the xpath expression as a string, then you could generate the same node set inside your extension using the umbraco.presentation.nodefactory methods. Then you can pass the C# generated xml back as an xpathnodeiterator.

    Depending on how flexible you want your extension to be, you could pass more parameters like mylib.GetDataStuff($currentPage/@id, 'some/xpath/here'). Or you could just hardcode your extension to always use currentpage as a startingpoint.

    Maybe if you tell a bit about what the goal is, then we can help determine the best alternative solution?

  • Warren Buckley 2106 posts 4836 karma points MVP ∞ admin hq c-trib
    Jan 30, 2009 @ 10:53
    Warren Buckley
    0

    Hello daniel Morten has some good advice.

    But its best for us to see the XSLT snippet & to try to understand what you are trying to achieve so we can help you out.

    Warren :)

  • Daniel Lindstrom 454 posts 271 karma points
    Jan 30, 2009 @ 11:30
    Daniel Lindstrom
    0

    [quote=mortenbock]I have not tried sending the actual nodeset to an extension, but you could try to rethink it a bit.

    If you pass the xpath expression as a string, then you could generate the same node set inside your extension using the umbraco.presentation.nodefactory methods. Then you can pass the C# generated xml back as an xpathnodeiterator.

    Depending on how flexible you want your extension to be, you could pass more parameters like mylib.GetDataStuff($currentPage/@id, 'some/xpath/here'). Or you could just hardcode your extension to always use currentpage as a startingpoint.

    Maybe if you tell a bit about what the goal is, then we can help determine the best alternative solution?[/quote]

    Of course! Fetching the nodeset in csharp didn't occur to me, propbably because I had already manipulated the node set in XSLT before trying to send it to csharp. If I rework the workflow I could probably get that solution to work. Will try it!

    The goal is to sort on data not stored in umbraco, for example page hits.

    Thanks!

  • Daniel Lindstrom 454 posts 271 karma points
    Feb 01, 2009 @ 14:37
    Daniel Lindstrom
    0

    [quote=mortenbock]
    If you pass the xpath expression as a string, then you could generate the same node set inside your extension using the umbraco.presentation.nodefactory methods. Then you can pass the C# generated xml back as an xpathnodeiterator.

    Depending on how flexible you want your extension to be, you could pass more parameters like mylib.GetDataStuff($currentPage/@id, 'some/xpath/here'). Or you could just hardcode your extension to always use currentpage as a startingpoint.[/quote]

    I am trying this solution right now, but I cannot figure out how to convert a nodeFactory.Node or Nodes to XML or XPathIterator, or the apply an xpath to it.

    Any help would be appreciated!

    Thanks!

  • Daniel Lindstrom 454 posts 271 karma points
    Feb 01, 2009 @ 14:45
    Daniel Lindstrom
    0

    Seems I can use umbraco.library.GetXmlNodeByXPath or library.GetXmlNodeById to get nodes as XpathNodeIterator.

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    Feb 01, 2009 @ 15:26
    Morten Bock
    0

    Take a look at the source for the umbraco.library.GetXmlNodeByXPath methods. They use the nodefactory internally.

  • Daniel Lindstrom 454 posts 271 karma points
    Feb 01, 2009 @ 17:03
    Daniel Lindstrom
    0

    OK Now I got it all working!

    One thing surprised me. If I do like this:

    //Get nodeset for nodeId:
    XPathNodeIterator xi = library.GetXmlNodeById(nodeId.ToString());

    //Create new data node
    XmlDocument xdAppend = new XmlDocument();
    XmlNode xn = xdAppend.CreateElement("data");
    XmlAttribute xaAppend = xdAppend.CreateAttribute("alias");
    xaAppend.Value = "xtra";
    xn.Attributes.Append(xaAppend);
    xn.InnerText = "testX";
    xdAppend.AppendChild(xn);

    //Add data node to nodeset from umbraco library:
    xi.Current.AppendChild(xn.CreateNavigator());

    Now to the surprising part: the new data node is actually accessible in XSLT if I do:


    So I do not have to worry about sending the manipulated dataset back from csharp to xslt using an iterator. I thought I was working on a copy of the cahced umbraco xml, but that does not seem to be the case.

    But of course, if the cached umbraco xml in memory is changed (for example republished) then the added data is lost.

    So, can I detect when the cached xml data is changed or recreated from db? Is there something like an ActionHandler for that? Or any other way?

    If so, I could run the code to add the external data at that time, not having to worry about that in my xslt macros.

  • Morten Bock 1867 posts 2140 karma points MVP 2x admin c-trib
    Feb 01, 2009 @ 17:31
    Morten Bock
    0

    Suprising find.

    Well, I'm not sure what would be the best practise here. I don't know if there is a "onCacheRefresh" event that you could tap into. If there is, you could use that, and then use the onPublish event handler to add your external data to the in memory xml, but it just feels a bit fishy tapping into the actual cache that way.

    If your external data only needs to be added when a node is published you could have umbraco store the information for you. Create some extra fields in your document type, and populate them on the publish event. But this could cause the external data to be the same for a long time.

    If you need real time external data, then i would try and stay away form messing with the on memory cache, and just copy the data to a new nodeset, so you could ad you data that way.

    A third possibility is to fetch the external data to a local xml file on a scheduled basis, and then use xslt extensions to sort the umbraco xml on basis of your own xml file.

  • Daniel Lindstrom 454 posts 271 karma points
    Feb 01, 2009 @ 20:33
    Daniel Lindstrom
    0

    First: many thanks for all the useful feedback Morten!

    [quote=mortenbock]Suprising find.

    Well, I'm not sure what would be the best practise here. I don't know if there is a "onCacheRefresh" event that you could tap into. If there is, you could use that, and then use the onPublish event handler to add your external data to the in memory xml, but it just feels a bit fishy tapping into the actual cache that way.[/quote]

    Agree, that was my feeling too, after the initial 'Wow, this was easy!'.

    [quote=mortenbock]
    If your external data only needs to be added when a node is published you could have umbraco store the information for you. Create some extra fields in your document type, and populate them on the publish event. But this could cause the external data to be the same for a long time.[/quote]

    I abandoned storing the data on the document node as the external data is updated several times a day.

    [quote=mortenbock]
    If you need real time external data, then i would try and stay away form messing with the on memory cache, and just copy the data to a new nodeset, so you could ad you data that way.

    A third possibility is to fetch the external data to a local xml file on a scheduled basis, and then use xslt extensions to sort the umbraco xml on basis of your own xml file.[/quote]

    Yes I think these would be the best options here. I think I'll do something like this:

    In xslt extension:

    Copy the nodeset. (maybe only the relevant parts of it?)
    Add the external data to the nodeset.
    Add the nodeset copy to the app cache, with a suitable expiration time.

    return a copy as an XPathNodeiterator

    On subsequent calls to the xslt extension try to get from cache first.



  • Christian Palm 277 posts 272 karma points
    Feb 05, 2009 @ 13:06
    Christian Palm
    0

    Example on how to send a Node back from your xslt helper method



    [code]namespace CPalm
    {
    class XsltHelper
    {
    private static XPathNavigator emptyNavigator = new XmlDocument().CreateNavigator();

    public static XPathNodeIterator CreateEmptyIterator()
    {
    return emptyNavigator.Select("*");
    }

    public static XPathNodeIterator TestNodeToXPathNodeIterator()
    {
    Node node = new Node(1);
    return NodeToXPathNodeIterator(node);
    }

    private static XPathNodeIterator NodeToXPathNodeIterator(Node node)
    {
    XPathNodeIterator returnValue;
    if (node != null)
    {
    XPathNavigator navigator = content.Instance.XmlContent.CreateNavigator();
    navigator.MoveToId(node.Id.ToString());
    returnValue = navigator.Select(".");
    }
    else
    {
    returnValue = CreateEmptyIterator();
    }
    return returnValue;
    }
    }
    }[/code]

Please Sign in or register to post replies

Write your reply to:

Draft