How to Consume Business Intelligence Data Within Yahoo! Widgets (NW7.0)[1]

of 31 /31
How-to Guide SAP NetWeaver 2004s How To… Consume BI Data within Yahoo Widgets January 2007 Version 1.3 Applicable Releases: SAP NetWeaver 2004s (Business Information Management - Enterprise Reporting, Query, and Analysis)

Transcript of How to Consume Business Intelligence Data Within Yahoo! Widgets (NW7.0)[1]

How-to Guide SAP NetWeaver 2004s

How To… Consume BI Data within Yahoo Widgets January 2007 Version 1.3 Applicable Releases: SAP NetWeaver 2004s (Business Information Management - Enterprise Reporting, Query, and Analysis)

© Copyright 2007 SAP AG. All rights reserved. No part of this publication may be reproduced or transmitted in any form or for any purpose without the express permission of SAP AG. The information contained herein may be changed without prior notice. Some software products marketed by SAP AG and its distributors contain proprietary software components of other software vendors. Microsoft, Windows, Outlook, and PowerPoint are registered trademarks of Microsoft Corporation. IBM, DB2, DB2 Universal Database, OS/2, Parallel Sysplex, MVS/ESA, AIX, S/390, AS/400, OS/390, OS/400, iSeries, pSeries, xSeries, zSeries, z/OS, AFP, Intelligent Miner, WebSphere, Netfinity, Tivoli, and Informix are trademarks or registered trademarks of IBM Corporation in the United States and/or other countries. Oracle is a registered trademark of Oracle Corporation. UNIX, X/Open, OSF/1, and Motif are registered trademarks of the Open Group. Citrix, ICA, Program Neighborhood, MetaFrame, WinFrame, VideoFrame, and MultiWin are trademarks or registered trademarks of Citrix Systems, Inc. HTML, XML, XHTML and W3C are trademarks or registered trademarks of W3C®, World Wide Web Consortium, Massachusetts Institute of Technology. Java is a registered trademark of Sun Microsystems, Inc. JavaScript is a registered trademark of Sun Microsystems, Inc., used under license for technology invented and implemented by Netscape. MaxDB is a trademark of MySQL AB, Sweden. SAP, R/3, mySAP, mySAP.com, xApps, xApp, and other SAP products and services mentioned herein as well as their respective logos are trademarks or registered trademarks of SAP AG in Germany and in several other countries all over the world. All other product and service names mentioned are the trademarks of their respective companies. Data

contained in this document serves informational purposes only. National product specifications may vary. These materials are subject to change without notice. These materials are provided by SAP AG and its affiliated companies ("SAP Group") for informational purposes only, without representation or warranty of any kind, and SAP Group shall not be liable for errors or omissions with respect to the materials. The only warranties for SAP Group products and services are those that are set forth in the express warranty statements accompanying such products and services, if any. Nothing herein should be construed as constituting an additional warranty. These materials are provided “as is” without a warranty of any kind, either express or implied, including but not limited to, the implied warranties of merchantability, fitness for a particular purpose, or non-infringement. SAP shall not be liable for damages of any kind including without limitation direct, special, indirect, or consequential damages that may result from the use of these materials. SAP does not warrant the accuracy or completeness of the information, text, graphics, links or other items contained within these materials. SAP has no control over the information that you may access through the use of hot links contained in these materials and does not endorse your use of third party web pages nor provide any warranty whatsoever relating to third party web pages. SAP NetWeaver “How-to” Guides are intended to simplify the product implementation. While specific product features and procedures typically are explained in a practical business context, it is not implied that those features and procedures are the only approach in solving a specific business problem using SAP NetWeaver. Should you wish to receive additional information, clarification or support, please refer to SAP Consulting. Any software coding and/or code lines / strings (“Code”) included in this documentation are only examples and are not intended to be used in a productive system environment. The Code is only intended better explain and visualize the syntax and phrasing rules of certain coding. SAP does not warrant the correctness and completeness of the Code given herein, and SAP shall not be liable for errors or damages caused by the usage of the Code, except if such damages were caused by SAP intentionally or grossly negligent.

- 1 -

1 Introduction Yahoo Widgets are great applications for allowing users to interact with systems or applications directly on their desktop. Within the SAP space, there are casual users of BI that may want metrics on a daily basis. Many customers run their businesses off one or two key reports, such as a daily sales report, or a simplified financial statement. Therefore, this guide provides a way to consume BI Data within Yahoo Widgets. Screenshot of Widget:

2 Scenarios As with any solution, the first thing you need to do is identify when to use the solution. The Yahoo Widgets solution is great for targeting your casual user. For example, many users have similar types of desktop applications to view their stock ticker every morning. This information is peripheral. You glance at it in the morning, but don’t really do anything or follow up unless your stock value changes drastically (either positive or negative). I’m proposing that key enterprise metrics be treated in a similar manner. For example, if a company uses daily sales numbers to measure performance, this metric should be pervasive within the organization. Users should see their metric peripherally every day when they log onto their machine, and should only follow up if they see unexpected numbers. The Yahoo Widget Application allows you to present this to the user in a very nice way. They won’t even know they are interacting with an SAP application! The example below will utilize a BI Query that provides daily sales results by Sales Organizations within a CPG company. Also, keep in mind that this widget renders the full BI dataset from the query. The widget size expands based on how much data is returned from the BI query. Therefore, you should only use the widget for small datasets.

3 Version History and Limitations Version 1.1 - Currently, this dynamic dataset only supports characteristics in the row and structures in the column

- 2 -

- Does not support structures in both rows and columns - Does not support structures and characteristics in both rows and columns - Does not support hierarchies - Does not support queries with mandatory variables Version 1.2 - Added support for all query datasets with 2 structures and n characteristics - Added support for structures in both rows and columns - Added support for structures and characteristics in both rows and columns - Does not support hierarchies - Does not support queries with mandatory variables Version 1.3 - Widget now refreshes when preferences are changed

4 Pre-requisites

4.1 Activate QueryViewData Web Service

The QueryViewData web service is a web service that allows you to interact with all your BI Data. It providers a simple access to query results as XML list output. Therefore, it is optimal for customer-specific development for front-end applications reading SAP BI data. For details, see this blog and the attached presentation: https://www.sdn.sap.com/irj/sdn/weblogs?blog=/pub/wlg/4332

1. Go to SICF and activate this web service: “/sap/bc/srt/rfc/sap/QUERY_VIEW_DATA”

- 3 -

2. Go to transaction WSCONFIG and enter service destination “QUERY_VIEW_DATA” and enter variant “query_view_data” and hit enter. Currently, there are no released services so create a new service.

3. Choose Save to release this web service.

4. Choose ICF Details -> External Aliases

- 4 -

5. Choose “New” to create a new external alias.

6. Enter external alias “/sap/bw/xml/soap/queryview” and enter description “SAP BI Web Service – XML Result Set”

7. Specify your security and user ID on

the “Logon data” tab.

- 5 -

8. Specify “/sap/bc/srt/rfc/sap/QUERY_VIEW_DATA” under the “Trg Element” tab.

9. Save your external alias.

10. Go to transaction WSADMIN -> Go to -> Administration Settings. Ensure that the path to your J2EE is specified here and save this.

- 6 -

11. Find your web service and choose the “Web service homepage”

12. Login to your ABAP system from the Web Service Navigator

13. Choose Test -> GetQueryViewData to test this service.

- 7 -

14. Enter and Infoprovider and Query and send the request to test this web service. Note: If the query has mandatory variables, those must be passed in the parameter. For the sake of this test, use a query without variables.

15. Ensure the request and response

are successful.

16. If you have issues, make sure you activate your Web Service and Interface in SE80

- 8 -

17. Here is an example of how to pass parameters for filter values using WEB API commands. We are passing the FILTER_IOBJNM=0D_CHANNEL and FILTER_VALUE=3.

18. Here is an example of how to pass parameters for variable values using WEB API commands. In this case, we are using a selection option variable. We are passing the following parameters: VAR_NAME_1=DISTGOP VAR_OPERATOR_1=EQ VAR_VALUE_LOW_EXT_1=3 VAR_VALUE_HIGH_EXT_1=5

4.2 Install Yahoo Widget Engine

The Yahoo Widget Engine is a pre-requisite to running these Widgets.

1. Go to http://widgets.yahoo.com/ and download and install the latest version of Yahoo’s Widget Engine.

- 9 -

4.3 Install Yahoo Widget Converter Widget The Yahoo Widget Converter allows you to compile or de-compile a widget.

1. Go to http://widgets.yahoo.com/workshop/ and download the widget converter.

5 The Step by Step Solution – Creating your Widget In this section, we’ll discuss how-to create the Yahoo Widget. All Yahoo Widgets are open source so the easiest way to start with widgets is look at other widgets that are accomplishing things similar to what you’re looking to accomplish. Therefore, this guide will provide a “template widget” that you can use to start building widgets to consume SAP BI data. Additionally, we’ll provide the basic steps to build a basic widget from scratch. This example shows how to build a “Daily Sales” widget off SAP BI data.

5.1 Design your basic User Interface There are two options for designing your user interface. A Yahoo Widget is just an XML document. Therefore, you can update this XML Document with an XML text editor of your choice. The other option is to use Adobe Photoshop Layers to build your user interface. Here is an example of the scenario using an XML document. To use Photoshop Layers, see the help on yahoo’s website.

- 10 -

1. Create a new folder within your “My Documents\My Widgets” called “BI Data”.

2. Create a new text document.

3. Name the new file “BI_Data.kon”.

- 11 -

4. Open your new “kon” file with Wordpad or a text/xml editor of your choice.

5. Now we have to create the opening and closing widget tags to define this XML file as a widget. Therefore, copy this code into your new widget and update the author, company, and commented description of your widget. For now, make sure debug mode is “on”.

<?xml version=1.0 encoding="utf-8"?> <widget version="1.1" minimumVersion="2.0" id="com.sap.queryviewdata.bi" author="Prakash Darji" company="SAP"> <debug>on</debug> <!-- Daily Sales Widget Version 1.1 - A widget to display Daily Sales by Sales Organization --> </widget>

6. Now to define the size and position of your widget, add the <window> tag. The width and height here will be the size of your widget.

<window> <title>Daily Sales Widget</title> <name>mainWindow</name> <width>50</width> <height>50</height> <shadow>0</shadow> <alignment>left</alignment> <visible>false</visible> <onFirstDisplay> mainWindow.hOffset = 10 + screen.availLeft; mainWindow.vOffset = (screen.availHeight + screen.availTop) - 87; </onFirstDisplay> </window>

- 12 -

7. Within your “BI Data” folder, create a new folder called “Images”. This is where the images for your widget will be stored.

8. Create a background image for your widget and store it in this folder. Name this image “background.png”. If you want, you can use this image:

background.png

9. Add the background image tag to your Widget within the <widget> tag.

<image src="Images/background.png"> <name>bevel</name> <width>50</width> <height>50</height> <hOffset>0</hOffset> <vOffset>0</vOffset> </image>

- 13 -

10. Save your widget and double click on the BI_Data.kon file. This should launch your widget in the Yahoo Widget Engine. Here you should see your debug window and the BI Data Widget!

5.2 Adding “preferences” tags Yahoo Widgets can have global preferences that are set by the user. For our “Daily Sales” widget, we will allow the user to specify their userid, password, and host they want to connect to. Therefore, developers can use this widget to connect to development, QA, and production systems.

1. Add the following preference tags to your “BI Data” widget.

<!--Define Preferences --> <preference> <name>User</name> <title>UserID:</title> <type>text</type> <defaultValue>BIM253_00</defaultValue> <description>User</description> </preference> <preference> <name>Password</name> <title>Password:</title> <type>text</type> <defaultValue>Welcome1</defaultValue> <description>Password</description> <secure>yes</secure> </preference> <preference> <name>host</name> <title>Host</title> <type>text</type> <defaultValue>cdphl338.phl.sap.corp:1080

- 14 -

</defaultValue> <description>host</description> </preference> <preference> <name>InfoCube</name> <title>InfoCube</title> <type>text</type> <defaultValue>0D_SD_C03</defaultValue> <description>InfoCube</description> </preference> <preference> <name>Query</name> <title>Query</title> <type>text</type> <defaultValue>PM_DAILY_SALES</defaultValue> <description>Query</description> </preference> <preference> <name>mode</name> <title>mode</title> <type>popup</type> <defaultValue>offline</defaultValue> <option>online</option> <optionValue>online</optionValue> <option>offline</option> <optionValue>offline</optionValue> <description>Widget Mode</description> </preference>

2. Save your widget. Go to the debug console and click “Reload”.

- 15 -

3. Right click on your BI Data Widget and click “Widget Preferences”.

4. You should see your preferences fields. Click Save.

5.3 Adding the “onload” Action The “onload” action is required for a widget and tells the widget what action to perform when the widget loads. In this case, we want to call the “query_view_data” web service and write the data to the data area we defined in the previous step. For this scenario, we are getting all our data from one BI query, but we could just as easily use multiple SAP BI queries by calling this web service multiple times. Also, we are using very basic authentication, but more advanced authentication is also possible.

5.3.1 Set the Window as Visible

- 16 -

1. Within your <widget> tag, add the following action tag to make the window visibility true on load of the widget.

<action trigger="onLoad"> <!-- mainWindow.visible = true; --> </action>

5.3.2 Create Javascript Include Include the library specified in the template widget and the next section.

1. Within your BI_Data folder, create another file called “global_include.js”.

2. Paste the include code which is attached at the bottom of this document into the include file.

SEE SECTION 6 for include code.

- 17 -

5.3.3 Call the SAP BI QueryViewData Web Service

1. Update the action to now write the data grid from the BI Dataset by calling the query view data web service.

<action trigger="onLoad"> <!-- include("global_include.js"); //Make Widget Window Visible mainWindow.visible = true; xmlDoc = getXML(); if(xmlDoc==undefined) { alert("error"); } else { var numHeaderRows = xmlDoc.evaluate("number(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/AxisInfo/item[Axis='000']/Nchars)"); if(isNaN(numHeaderRows)) { numHeaderRows = 1; } var numRows = xmlDoc.evaluate("number(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/AxisInfo/item[Axis='001']/Ncoords)"); if(isNaN(numRows)) { numRows = 1; } numRows = numRows + numHeaderRows; var leadColumns = xmlDoc.evaluate("number(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/AxisInfo/item[Axis='001']/Nchars)"); if(isNaN(leadColumns)) { leadColumns = 0; } var numColumns = xmlDoc.evaluate("number(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/AxisInfo/item[Axis='000']/Ncoords)"); if(isNaN(numColumns)) { numColumns = 1; } numColumns = numColumns + leadColumns;

- 18 -

//Declare Array var dataset = new Array(); for(i = 0; i < numRows; i++) { dataset[i] = new Array(); } createTable(xmlDoc, numRows, numColumns, numHeaderRows, leadColumns); resizeCol(); writeTitle(xmlDoc.evaluate("string(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/TextSymbols/item[SymName='REPTXTLG']/SymValue)")); } -->

</action>

5.4 Turn off Debug Mode

1. Update the debug tag to be “off”. <debug>off</debug>

- 19 -

5.5 Compile your Widget!

1. Run the Widget Converter

6 The Final Widget

6.1 Here is an example of the Final Daily Sales Widget

<?xml version=1.0 encoding="utf-8"?> <widget version="1.1" minimumVersion="2.0" id="com.sap.queryviewdata.bi" author="Prakash Darji" company="SAP"> <debug>off</debug> <!-- Daily Sales Widget Version 1.1 - A widget to display Daily Sales by Sales Organization --> <window> <title>Daily Sales Widget</title> <name>mainWindow</name> <width>50</width> <height>50</height> <shadow>0</shadow> <alignment>left</alignment> <visible>false</visible> <onFirstDisplay> mainWindow.hOffset = 10 + screen.availLeft; mainWindow.vOffset = (screen.availHeight + screen.availTop) - 87; </onFirstDisplay> </window> <image src="Images/background.png"> <name>bevel</name> <width>50</width> <height>50</height> <hOffset>0</hOffset> <vOffset>0</vOffset>

- 20 -

</image> <!--Define Preferences --> <preference> <name>User</name> <title>UserID:</title> <type>text</type> <defaultValue>BIM253_00</defaultValue> <description>User</description> </preference> <preference> <name>Password</name> <title>Password:</title> <type>text</type> <defaultValue>Welcome1</defaultValue> <description>Password</description> <secure>yes</secure> </preference> <preference> <name>host</name> <title>Host</title> <type>text</type> <defaultValue>cdphl338.phl.sap.corp:1080</defaultValue> <description>host</description> </preference> <preference> <name>InfoCube</name> <title>InfoCube</title> <type>text</type> <defaultValue>0D_SD_C03</defaultValue> <description>InfoCube</description> </preference> <preference> <name>Query</name> <title>Query</title> <type>text</type> <defaultValue>PM_DAILY_SALES</defaultValue> <description>Query</description> </preference> <preference> <name>mode</name> <title>mode</title> <type>popup</type> <defaultValue>offline</defaultValue> <option>online</option> <optionValue>online</optionValue> <option>offline</option> <optionValue>offline</optionValue> <description>Widget Mode</description> </preference> <action trigger="onLoad">

- 21 -

<!-- include("global_include.js"); //Make Widget Window Visible mainWindow.visible = true; xmlDoc = getXML(); if(xmlDoc==undefined) { alert("error"); } else { var numHeaderRows = xmlDoc.evaluate("number(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/AxisInfo/item[Axis='000']/Nchars)"); if(isNaN(numHeaderRows)) { numHeaderRows = 1; } var numRows = xmlDoc.evaluate("number(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/AxisInfo/item[Axis='001']/Ncoords)"); if(isNaN(numRows)) { numRows = 1; } numRows = numRows + numHeaderRows; var leadColumns = xmlDoc.evaluate("number(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/AxisInfo/item[Axis='001']/Nchars)"); if(isNaN(leadColumns)) { leadColumns = 0; } var numColumns = xmlDoc.evaluate("number(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/AxisInfo/item[Axis='000']/Ncoords)"); if(isNaN(numColumns)) { numColumns = 1; } numColumns = numColumns + leadColumns; //Declare Array var dataset = new Array(); for(i = 0; i < numRows; i++) { dataset[i] = new Array(); } createTable(xmlDoc, numRows, numColumns, numHeaderRows, leadColumns); resizeCol(); writeTitle(xmlDoc.evaluate("string(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/TextSymbols/item[SymName='REPTXTLG']/SymValue)")); } --> </action>

- 22 -

<action trigger="onPreferencesChanged"> <![CDATA[ alert("changed"); xmlDoc = getXML(); if(xmlDoc==undefined) { alert("error"); } else { var numHeaderRows = xmlDoc.evaluate("number(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/AxisInfo/item[Axis='000']/Nchars)"); if(isNaN(numHeaderRows)) { numHeaderRows = 1; } var numRows = xmlDoc.evaluate("number(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/AxisInfo/item[Axis='001']/Ncoords)"); if(isNaN(numRows)) { numRows = 1; } numRows = numRows + numHeaderRows; var leadColumns = xmlDoc.evaluate("number(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/AxisInfo/item[Axis='001']/Nchars)"); if(isNaN(leadColumns)) { leadColumns = 0; } var numColumns = xmlDoc.evaluate("number(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/AxisInfo/item[Axis='000']/Ncoords)"); if(isNaN(numColumns)) { numColumns = 1; } numColumns = numColumns + leadColumns; //Declare Array var dataset = new Array(); for(i = 0; i < numRows; i++) { dataset[i] = new Array(); } createTable(xmlDoc, numRows, numColumns, numHeaderRows, leadColumns); resizeCol(); writeTitle(xmlDoc.evaluate("string(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/TextSymbols/item[SymName='REPTXTLG']/SymValue)")); } ]]> </action> </widget>

- 23 -

6.2 Javascript include /** * Global Include */ function callWebService() { //Create Web Service URL from preferences var infocube = preferences.InfoCube.value; var query = preferences.Query.value; var webservice = "http://" + preferences.host.value + "/sap/bc/srt/rfc/sap/QUERY_VIEW_DATA?sap-client=003&wsdl=1.1" + "&sap-user=" + preferences.User.value + "&sap-password=" + preferences.Password.value; var action; //Build SOAP Envelope String to pass to the web service var SOAPEnvelope = "<SOAP-ENV:Envelope" + " xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'" + " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'" + " xmlns:xs='http://www.w3.org/2001/XMLSchema'>" + "<SOAP-ENV:Header>" + "<sapsess:Session xmlns:sapsess='http://www.sap.com/webas/630/soap/features/session/'>" + "<enableSession>true</enableSession>" + "</sapsess:Session></SOAP-ENV:Header>" + "<SOAP-ENV:Body>" + "<ns1:GetQueryViewData xmlns:ns1='urn:sap-com:document:sap:soap:functions:mc-style'>" + "<Infoprovider>" + infocube + "</Infoprovider>" + "<Query>" + query + "</Query>" + "</ns1:GetQueryViewData>" + "</SOAP-ENV:Body>" + "</SOAP-ENV:Envelope>"; // Create SOAP Request var request = new XMLHttpRequest(); request.open("POST", webservice, false); // Set Header Information request.setRequestHeader ("SOAPAction", action); request.setRequestHeader ("Content-Type", "text/xml"); //Execute the SOAP request and send the SOAPEnvelope String request.send(SOAPEnvelope); return request; } function work_offline() {

- 24 -

//Use Local file try { //Test Document for 1 characteristic in row and 1 structure in column var xmlDoc = XMLDOM.parse(filesystem.readFile("sample_data/xmldoc_01.xml")); //Test Document for 2 characteristics in row and 1 structure in column //var xmlDoc = XMLDOM.parse(filesystem.readFile("sample_data/xmldoc_02.xml")); //Test Document for 1 structure in row and 1 structure in column //var xmlDoc = XMLDOM.parse(filesystem.readFile("sample_data/xmldoc_03.xml")); //Test Document for 2 structures in row and nothing in column //var xmlDoc = XMLDOM.parse(filesystem.readFile("sample_data/xmldoc_04.xml")); //Test Document for nothing in row and 2 structures in column //var xmlDoc = XMLDOM.parse(filesystem.readFile("sample_data/xmldoc_05.xml")); //Test Document for 1 structure and 2 characteristics in row and 1 structure in column //var xmlDoc = XMLDOM.parse(filesystem.readFile("sample_data/xmldoc_06.xml")); //Test Document for 1 structure in row and 1 structure with 2 characteristics in column //var xmlDoc = XMLDOM.parse(filesystem.readFile("sample_data/xmldoc_07.xml")); //Test Document for 1 structure with 2 characteristics in row and 1 structure with 2 characteristics in column //var xmlDoc = XMLDOM.parse(filesystem.readFile("sample_data/xmldoc_08.xml")); //Test Document for nothing in row 1 structure in column //var xmlDoc = XMLDOM.parse(filesystem.readFile("sample_data/xmldoc_09.xml")); return xmlDoc; } catch( e ) { print( e ); } } function getXML() { if (preferences.mode.value == 'offline') { xmlDoc = work_offline(); return xmlDoc; } else

- 25 -

{ request = callWebService(); if (request.status != 200) { alert("Cannot load BI Query. Please change to offline mode in preferences"); } else { //Create an XML Document and string with data returned from web service var xmlDoc = request.responseXML; var textDoc = request.responseText; return xmlDoc; } } } function PadInt(i,width,pad) { if( i < 0 || (i + "").length >= width ) return i; return PadInt(pad + i,width,pad); } function createTable(xmlDoc, numRows, numColumns, numHeaderRows, leadColumns) { var row; var col; var init_colposition = 18; var init_rowposition = 65; var colposition = 18; var rowposition = 65; var row_step = 15; var col_step = 115; j = 1; k = 1; m = 2; //Create Vertical Scroll Bar var scrollFrame = new Frame( mainWindow ); scrollFrame.vOffset = colposition; scrollFrame.hOffset = rowposition + row_step; scrollFrame.hOffset = rowposition + row_step; //Write Dataset for(row = 0; row < numRows; row++) { for(col = 0; col < numColumns; col++) { dataset[row][col] = new Text(); dataset[row][col].hOffset = colposition; dataset[row][col].vOffset = rowposition; dataset[row][col].alignment = "left"; dataset[row][col].size = 12; dataset[row][col].font = "Arial"; dataset[row][col].color = "#FFFFFF"; dataset[row][col].visible = true;

- 26 -

//Write Headers if(row < numHeaderRows && col < leadColumns) { index = col + 1; dataset[row][col].data = xmlDoc.evaluate("string(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/AxisInfo/item[Axis='001']/Chars/item[" + index + "]/Caption)"); dataset[row][col].style = "bold"; } if (row < numHeaderRows && col >= leadColumns) { index = k; dataset[row][col].data = xmlDoc.evaluate("string(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/AxisData/item[Axis='000']/Set/item[" + index + "]/Caption)"); dataset[row][col].style = "bold"; k = k + numHeaderRows; if(k > ((numColumns-leadColumns) * numHeaderRows)) { k = m; m++; } } //Write Lead Columns if (row >= numHeaderRows && col < leadColumns) { index = (col) + (row - numHeaderRows) * (leadColumns) + 1; dataset[row][col].data = xmlDoc.evaluate("string(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/AxisData/item[Axis='001']/Set/item[" + index + "]/Caption)"); scrollFrame.addSubview(dataset[row][col]); } //Write DataSet if (row >= numHeaderRows && col >= leadColumns) { //cell_ordinal = (col) + (row-1) * numColumns - 1; //alert(cell_ordinal); itemvalue = PadInt(j, 6, "0" ); dataset[row][col].data = xmlDoc.evaluate("string(soap-env:Envelope/soap-env:Body/n0:GetQueryViewDataResponse/CellData/item[" + itemvalue + "]/FormattedValue)"); scrollFrame.addSubview(dataset[row][col]); j++; } colposition = colposition + col_step; } colposition = init_colposition; rowposition = rowposition + row_step; //Increase Height of Widget if(mainWindow.height < rowposition) { mainWindow.height = rowposition + row_step + 30; bevel.height = mainWindow.height;

- 27 -

} } } function writeTitle(w_title) { title = new Text(); title.data = w_title; title.alignment = "right"; title.size = 20; title.color = "#FFFFFF"; title.hOffset = mainWindow.width -15; title.vOffset = 30; } function resizeCol() { var colposition = 18; var col_buffer = 15; for(col = 0; col < numColumns; col++) { var colSize = 0; //Find minimum column size for(row = 0; row < numRows; row++) { colSize = Math.max(colSize, dataset[row][col].width); } for(row = 0; row < numRows; row++) { dataset[row][col].hOffset = colposition; } colposition = colposition + colSize + col_buffer; //Increase Widget width based on dataset if(mainWindow.width < colposition) { mainWindow.width = colposition + col_buffer + 10; bevel.width = mainWindow.width; } } }

6.3 Here is a template widget you can copy to call BI data generically

BI_DATA.widget

- 28 -

7 Appendix

7.1 References http://widgets.yahoo.com/workshop/

http://www.sdn.sap.com/irj/sdn/howtoguides