3

I have an XML file that I am transforming via XSLT. I am passing an XML as parameter to the XSLT via C#. The parameter's name is attachment and it contains XML. It is written as follows:

StringWriter sw = new StringWriter(); 
XmlTextWriter w = new XmlTextWriter(sw); 
w.WriteStartElement("root"); 
if (!string.IsNullOrEmpty(sWordFileName)) { 
    w.WriteStartElement("mylink", sWordFileName); 
    w.WriteEndElement(); 
}
if (!string.IsNullOrEmpty(sPDFFileName)) { 
    w.WriteStartElement("mylink", sPDFFileName);
    w.WriteEndElement();
}
w.Close();
XPathDocument doc = new XPathDocument(new StringReader(sw.ToString()));
XPathNavigator nav = doc.CreateNavigator();
_exportSet[currentExportSet].Format.ParamList["attachment"] = nav.Select("./*");

My xml parameter looks like

<root><attachment xmlns=file1><attachment xmlns=file2></root>

Now in XSLT I need to iterate through this XML param and create a link.

Here is my XSLT

<?xml version="1.0" encoding="utf-8"?> 
    <xsl:stylesheet version="2.0" xmlns:xsl="w3.org/1999/XSL/Transform"
        xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
        xmlns:my-scripts="urn:my-scripts" 
        xmlns="factiva.com/fcs/schemas/newsSummaries">

        <xsl:param name="attachment"/>
        <xsl:for-each select="$attachment">  
            <a target="_blank" href="#"><xsl:copy-of select="."/></a>  
         </xsl:for-each>
     </xsl:stylesheet>

But it doesn't create a link.

jvm
  • 1,662
  • 8
  • 27
  • 46
  • Why are you asking for the reason that your "code" is not working? The actual value of the parameter you clain is passed to the transformation is not even an well-formed XML document -- you should have got an exception at the time you wanted to load this into an XmlDocument. Not to speak about the XSLT stylesheet. The best recommendation is that you need to read and learn at least the basics of XML, XPath and XSLT. – Dimitre Novatchev Feb 24 '11 at 00:18
  • Now the question is well defined as MS specific XSLT processor. I think that @Dimitre can help. –  Feb 24 '11 at 14:09

5 Answers5

2

An XSLT parameter is different than an XML tag name. Parameters are passed using the tag as described here.

As stated in the comments below, this problem is not too different from what is provided in the link above.

StringWriter sw = new StringWriter(); 
XmlTextWriter w = new XmlTextWriter(sw); 
w.WriteStartElement("root"); 
if (!string.IsNullOrEmpty(sWordFileName)) { 
    w.WriteStartElement("attachment", sWordFileName); 
    w.WriteAttributeString("name", sWordFileName);
    w.WriteEndElement(); 
}
if (!string.IsNullOrEmpty(sPDFFileName)) { 
    w.WriteStartElement("attachment");
    w.WriteAttributeString("name", sPDFFileName);
    w.WriteEndElement();
}
w.WriteEndElement();
w.Close();
XPathDocument doc = new XPathDocument(new StringReader(sw.ToString()));
XPathNavigator nav = doc.CreateNavigator();

XsltArgumentList xslArg = new XsltArgumentList();
xslArg.AddParam("attachment","",nav);

Here would be XSL to match per Accessing parameters which contain mark-up:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" 
   xmlns:xsl="w3.org/1999/XSL/Transform"
   xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
   xmlns:my-scripts="urn:my-scripts" 
   xmlns="factiva.com/fcs/schemas/newsSummaries">
    <xsl:param name="attachment" />

    <xsl:template match="/">
        <xsl:apply-templates select="$attachment"/>
    </xsl:template>
    <xsl:template match="attachment">
        <a target="_blank" href="{@name}">{@name}</a>
    </xsl:template>

</xsl:stylesheet>
justkt
  • 14,610
  • 8
  • 42
  • 62
  • @jatin - I assume that is your XSL - but beyond that I'm not quite sure what your comments indicate? – justkt Feb 23 '11 at 18:49
  • attachment is passed as param and it contains xml like which i need to iterate and display as link – jvm Feb 23 '11 at 18:51
  • basically, i am doing XSLT transformation. Now my requirement is, i need to create some links which will be decided runtime. So i programatically create XML and pass it to XML as we don't have array in XSLT – jvm Feb 23 '11 at 18:55
  • Ok. I use c#. I have one big XML. let me call it myXML. Now i am applying XSLT on myXML. I need to pass some parameters during XSLT transformation. One of the parameter name is "attachment" which i declare as in my XSLT. This parameter value i created by c# and it looks like . Now, i my xslt i need to iterate inside this parameter and create tag – jvm Feb 23 '11 at 19:05
  • @jatin - updated based on what I've found, but you may want to add this information to your question so others can answer and possibly change your tags to include C#. – justkt Feb 23 '11 at 19:15
  • @jatin - do you get any errors from the parser? Do you have any debug? – justkt Feb 23 '11 at 19:41
  • No. i don't get any errors. do i need to use – jvm Feb 23 '11 at 19:44
  • @jatin - I'd try it and see. Usually when debugging a transform I start removing pieces until I see that the transform is working with a minimal set, then add information back in. – justkt Feb 23 '11 at 19:46
  • @justkt: It's ok to pass XML node set as parameter. Please, don't confuse people! –  Feb 23 '11 at 20:09
  • @Alejandro - I understand, I just didn't understand at first why one would do that, because the question at first only showed a small snippet that looked like all the author needed was to transform a small XML string. The comments here are left from that earlier revision. – justkt Feb 23 '11 at 20:12
  • @justkt: Passing a node set as parameter is handy for structured data (like maps). –  Feb 23 '11 at 20:46
  • this is how i pass param to xslt StringWriter sw = new StringWriter(); XmlTextWriter w = new XmlTextWriter(sw); w.WriteStartElement("root"); if (!string.IsNullOrEmpty(sWordFileName)) { w.WriteStartElement("mylink", sWordFileName); w.WriteEndElement(); } if (!string.IsNullOrEmpty(sPDFFileName)) { w.WriteStartElement("mylink", sPDFFileName); w.WriteEndElement(); } w.Close(); XPathDocument doc = new XPathDocument(new StringReader(sw.ToString())); XPathNavigator nav = doc.CreateNavigator(); _exportSet[currentExportSet].Format.ParamList["attachment"] = nav.Select("./*");am i doing something wrong – jvm Feb 24 '11 at 12:46
  • @jatin - I have added this information to the question, where other answerers can see it. You should see [@Chris's answer](http://stackoverflow.com/questions/5095483/how-to-iterate-through-xml-param-in-xslt/5095542#5095542), which corrects your XML and XSLT and may help significantly. [@Alejandro](http://stackoverflow.com/questions/5095483/how-to-iterate-through-xml-param-in-xslt/5096546#5096546) has presented you a *working* example. – justkt Feb 24 '11 at 13:13
  • @justkt: Your code isn't addressing the question as it's not passing a node set parameter. Please, do correct that. –  Feb 24 '11 at 14:03
  • @Alejandro - I don't know why my answer was accepted, as my comments pointed to your answer and Chris's. I will address my answer. – justkt Feb 24 '11 at 14:04
2

It should read <xsl:for-each select="attachment">.... There is no $ sign because attachment is the name of an XML element, not a variable.


EDIT after you've given the full XSLT and XML.

There are several problems with your XML:

  • All tags should be closed.
  • You may not use the xmlns for anything else that it's meant for — namespaces.
  • You must have double quotes around the attribute values

So a correct version of the XML file would be (for instance):

<root>
  <attachment ptr="file1" />
  <attachment ptr="file2" />
</root>

The XSLT file has some issues too:

  • The xsl namespace should be bound to the exact URI http://www.w3.org/1999/XSL/Transform.
  • You must have at least a template so that the XSLT transform processes your input XML document.

A correct version would be, for instance:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/root">
    <xsl:for-each select="attachment">  
      <a target="_blank" href="{@ptr}"><xsl:value-of select="@ptr" /></a>  
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

I'm not sure it is exactly what you want, but for the above document it produces the following fragment:

<a target="_blank" href="file1">file1</a>
<a target="_blank" href="file2">file2</a>
ChrisJ
  • 5,161
  • 25
  • 20
  • @ChrisJ: `attachment` XPath expression would select `attachment` children of context node (parameter reference not used) –  Feb 23 '11 at 20:43
  • @Alejandro: I've updated the answer after you've added the full XSLT. – ChrisJ Feb 23 '11 at 22:45
  • @ChrisJ: Now is better. You wrote: *"You must have at least a template so that the XSLT transform processes your input XML document"*. That's not true. Do test it. Besides that you didn't address the question title. –  Feb 23 '11 at 23:04
  • @Alejandro: I tested your files (not with C#, with xsltproc), and it sure did not work; the processor reported the aforementioned errors... Please tell us more explicitly what your question is, what the expected result is. – ChrisJ Feb 23 '11 at 23:10
  • @ChrisJ: I'm not the OP. @jatin is. –  Feb 23 '11 at 23:11
  • @Alejandro: oops, sorry about that. Then, jatin, please tell us if this answer helps you, and if not, what you were expecting. – ChrisJ Feb 23 '11 at 23:16
2

You can pass any XPath/XSLT data type as parameters. How to do that entirely depends on the XSLT processor implementation.

As proof this stylesheet, with any input (not used):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="attachment" select="document('parameter.xml')/root"/>
    <xsl:template match="/">
        <xsl:apply-templates select="$attachment"/>
    </xsl:template>
    <xsl:template match="attachment">
        <a target="_blank" href="{@href}">Link</a>
    </xsl:template>
</xsl:stylesheet>

And parameter.xml resource as:

<root>
    <attachment href="file1"/>
    <attachment href="file2"/>
</root> 

Output:

<a target="_blank" href="file1">Link</a>
<a target="_blank" href="file2">Link</a>
0

You would want to put the value of your attribute that has the link in it like so:

<xsl:value-of select="@YourAttribute"/>

This selects an attribute for the current xml element.

sturdynut
  • 628
  • 4
  • 7
0

The code you posted is somewhat incorrect. Where are the quotes, what is $attachment? You probably forgot to mention namespace, to select correctly, you need to write select="//file1:attachment" or sth like that.

vissi
  • 2,325
  • 1
  • 19
  • 26