views:

723

answers:

3

I'm trying to use a data view web part (via SPD 2007) to consume the results of a SOAP-based web service and render portions of said results using XSL transforms. The problem I'm having is that the designer isn't much help because the schema for the web service doesn't actually include the elements of the results, so there's no way to drag and drop from the data source into the web part, and the manual transforms I've attempted aren't working.

Here is the definition of the web service:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"&gt;
  <soap:Body>
    <GetQuote xmlns="http://www.webserviceX.NET/"&gt;
      <symbol>string</symbol>
    </GetQuote>
  </soap:Body>
</soap:Envelope>

And the definition of the response:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"&gt;
  <soap:Body>
    <GetQuoteResponse xmlns="http://www.webserviceX.NET/"&gt;
      <GetQuoteResult>string</GetQuoteResult>
    </GetQuoteResponse>
  </soap:Body>
</soap:Envelope>

The query definition is no problem - you just supply a stock ticker symbol as a string. You'll see what I'm talking about in the results, though. It defines the result as just a string.

In SPD2007, the data source pretty much only includes soap:Envelope/soap:Body/GetQuoteResponse/GetQuoteResult, but the actual results contained in the result string look like this:

<StockQuotes>
  <Stock>
    <Symbol>MSFT</Symbol>
    <Last>28.465</Last>
    <Date>3/3/2010</Date>
    <Time>1:24pm</Time>
    <Change>+0.005</Change>
    <Open>28.52</Open>
    <High>28.61</High>
    <Low>28.35</Low>
    <Volume>28380812</Volume>
    <MktCap>249.7B</MktCap>
    <PreviousClose>28.46</PreviousClose>
    <PercentageChange>+0.02%</PercentageChange>
    <AnnRange>14.87 - 31.50</AnnRange>
    <Earns>1.815</Earns>
    <P-E>15.68</P-E>
    <Name>Microsoft Corpora</Name>
  </Stock>
</StockQuotes>

I've tried setting up an XSL stylesheet like this in the data view web part:

<xsl:stylesheet xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
                        xmlns:ddw1="http://www.webserviceX.NET/"
                        version="1.0"
                        exclude-result-prefixes="xsl msxsl ddwrt"
                        xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
                        xmlns:asp="http://schemas.microsoft.com/ASPNET/20"
                        xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer"
                        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                        xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                        xmlns:SharePoint="Microsoft.SharePoint.WebControls"
                        xmlns:ddwrt2="urn:frontpage:internal">
            <xsl:output method="html" indent="yes"/>
            <xsl:param name="dvt_apos">'</xsl:param>
            <xsl:template match="/soap:Envelope/soap:Body/ddw1:GetQuoteResponse">
                <xsl:value-of select="*" />             
            </xsl:template>
        </xsl:stylesheet>

This does pretty much what you would expect: it renders the entire result string. However, if I replace

<xsl:template match="/soap:Envelope/soap:Body/ddw1:GetQuoteResponse">
  <xsl:value-of select="*" />               
</xsl:template>

with

<xsl:template match="/soap:Envelope/soap:Body/ddw1:GetQuoteResponse">
  <xsl:value-of select="//Symbol" />                
</xsl:template>

I get nothing. What's going on? how do I use XSL to pick out the XML in the string result without a schema?

+2  A: 

Looks like the results are a string, not XML which would require processing as such. I cannot be sure without looking at the result xml.

Try adding <xmp><xsl:copy-of select="." /></xmp> and posting the results.

Can you remove the match on soap:Envelope etc and replace with match "*".

Then inside that add a

<p>Symbol:<xsl:value-of select="/StockQuotes/Stock/Symbol" /></p> 

If that does not provide values, the matching is not correct. Also try

<p>Symbol:<xsl:value-of select="/soap:Envelope/soap:Body/ddw1:GetQuoteResponse/StockQuotes/Stock/Symbol" /></p>

At the end of the day you are wanting to get something like (without seeing the raw xml I cannot be sure) This is all for debugging.

Nat
it renders pretty much like my select="*" template.
Ben Collins
If I can see the raw xml of the response I can try find out what is going on.
Nat
+1  A: 

In looking at the service you are using it does return the values in a string with < making it look like XML. I can't imagine why they would do this, but you'll need to parse the string as XML in order to process it. There is no native XSLT function to do this, so you'll have to use an extension function. I don't know of one from Microsoft so you'll have to write your own.

Fortunately there is a good example in this post of this exact question. This person ended up using a custom extension function written in c# to convert the string to XML and then pass it back to the XSLT for regular processing. The custom function they use is:

<msxml:script language="CSharp" implements-prefix="cd">
<msxml:using namespace="System.IO" />

    public XPathNodeIterator parse(string data) {
        if(data==null || data.Length==0) {
            data="&lt;Empty /&gt;";
        }
        StringReader stringReader = new StringReader(data);
        XPathDocument xPathDocument = new XPathDocument(stringReader);
        XPathNavigator xPathNavigator = xPathDocument.CreateNavigator();
        XPathExpression xPathExpression = xPathNavigator.Compile("/");
        XPathNodeIterator xPathNodeIterator = xPathNavigator.Select(xPathExpression);
        return xPathNodeIterator;
    }
</msxml:script>

And then you call the function on your string:

<xsl:variable name="theXML" select="string(/string)" />
<xsl:variable name="list" select="cd:parse($theXML)" />

I can't guarantee that the custom function will work exactly the way you need it, but it should hopefully get you close.

Peter Jacoby
A: 

I strongly suggest you take a look at this presentation, that covers advanced xsl editing for dataview webparts, it should make your live easier (drag&drop xslt editing, with instant-preview in the editor)

Kind regards, Rik

Rik