Create SASLibrary Metadata with Extended Attributes Programmatically - sas

Due to a requirement in creating multiple SAS libraries from time to time in the MC, I am trying to figure out how to do this programmatically. These libraries are pointing to external databases. So far, using the available examples I was able to use the following code to create library metadata.
proc metadata in='<AddMetadata>
<Metadata>
<SASLibrary
Name="Test Library"
Desc="This is a test"
Folder="\Shared Data\Test"
Engine="DB2"
IsDBMSLibname="1"
IsHidden="0"
Libref="testlib"
IsPreassigned="0"
PublicType="Library">
</SASLibrary>
</Metadata>
<Reposid>A0000001.A849HGWS</Reposid>
<NS>SAS</NS>
<Flags>268435456</Flags>
<Options/>
</AddMetadata>
';
However this is still missing the resource template, schema name, location (folder name). Is there any way we can add these programmatically as well? Also anyway to update the access templates? Any attributes that I can assign these values to when calling proc metadata? Thanks in advance.

You can use the DATA Step function metadata_newobj("SASLibrary", to programmatically create your libraries. Check the documentation for "METADATA_NEWOBJ Function" for further examples of setting the attributes of the library via rc=metadata_setattr(luri,

Functions are ok but troublesome since you must invoke bunch of them to get desired result. XML as a template works best.
If you have access to SAS Management Console I am recommending enabling Metadata Inspector plugin.
cp -r $SASHOME/SASManagementConsole/9.4/plugins/advanced/omitoolsmc $SASHOME/SASManagementConsole/9.4/plugins/
Then in SASMC you are able to browse metadata of all objects using XML queries. Just go to Tools -> XML Metadata Interface.
Below is example XML fetched using this tool. To place this library in specific folder you need to know folder metadata id (Tree association). Same goes to associating library with a server context (DeployedComponents association) and/or DB2 server.
Of course you need only necessary tags. You can ommit empty ones.
<SASLibrary Name="DB2 Library" Desc="Library description" Engine="DB2" IsDBMSLibname="1" IsHidden="0" IsPreassigned="0" Libref="DB2LIB" PublicType="Library">
<AccessControls/>
<Aliases/>
<AliasFor/>
<Changes/>
<CustomAssociations/>
<DefaultLogin/>
<DeployedComponents>
<ServerContext Id="associated context meta id" />
</DeployedComponents>
<Documents/>
(...)
<Timestamps/>
<Trees>
<Tree Id="folder meta id"/>
</Trees>
<TSObjectNamespace/>
<UsedByPackages/>
<UsedByPrototypes/>
<UsingPackages/>
<UsingPrototype/>
<Variables/>
</SASLibrary>

Related

SAS - Create new libraries nested inside WORK

tl;dr: Can SAS libraries be nested within one another in the Enhanced Editor Explorer?
I am working with code which generates a plethora of data sets. Although there are many individual data sets, they can be grouped into various categories. For instance, perhaps 30 of them are incoming "raw" data, another 50 are analysis "results" and the remaining 20 are "intermediate" steps.
Currently, all 100 data sets reside in the Work directory. They have been well named so that they appear next to one another in the SAS Explorer window. However, I would prefer to organize them in folders.
One way to do this is to create new directories within the temporary Work folder.
%let dirWORK = %sysfunc(pathname(Work));
options dlcreatedir;
libname raw "&dirWORK./raw";
libname interm "&dirWORK./intermediate";
libname results "&dirWORK./results";
As sub-directories of Work, these directories and their contents will be deleted when the session ends. This is agreeable.
Not agreeable is how the raw, iterm, and results libraries appear one level up in 'Active Libraries' instead of within the 'Contents of "Work"'. This behavior is somewhat counter-intuitive and awkward.
Is there a way to view the sub-folders of Work within the 'Contents
of "Work"' in the SAS Explorer?
Perhaps there's another way to separate the data sets (DCREATE?) which causes the Explorer window to behave like a typical file browser?
Libraries can contain many things.. But not other libraries. Your 'Active Libraries' will always show your (available) list of libraries at the same level, regardless of where or how they were defined:
One option if you'd like to view your datasets like a typical file browser is to use the Explorer window. Just click View / Explorer, and navigate to your datasets that way..
eg:
%let dirWORK =C:/temp/work;
options dlcreatedir;
libname raw "&dirWORK./raw";
libname interm "&dirWORK./intermediate";
libname results "&dirWORK./results";
data raw.test;
set sashelp.class;
run;
SAS librefs are just single words, so by definition there is no heirarchy. You could try using librefs that will place them next to each other alphabetically? Perhaps WORKIN, WORKMID, WORKOUT. Then they would sort in logical order.
You could use a file explorer to browse the directory structure you have created, but I don't think the SAS Explorer tool in SAS Display Manager can handle that.
DMS does have a file explorer tool you could try. You can start directly on your current WORK directory by running this command from the command line of any window, or via the DM statement in a program.
exproot dir="%sysfunc(pathname(work))" title="Work Directory"
There appears to be no ideal solution. The best I could devise requires the use of two part names, a non-trivial amount of extra code, a custom setup, and is potentially confusing to other programmers. The easiest configuration appears to be the default behavior: simply dumping all data sets in the Work library and sifting through all of them.
For prosperity, here is the best solution I could devise to organize things.
Understanding the Display Manager and Explorer Window
The Display Manager (DM) controls the various windows in the Enhanced Editor. This includes windows such as log, results, pgm, output and explorer. It is the latter which is of principle interest here.
A user may configure windows per session using the menus. There exist, however, a set of commands which may be used to automatically configure the DM for each session. When used with the AUTOEXEC.sas facility, this allows the user to 'permanently' configure the SAS editor to their preferences.
The default explorer view for the Enhanced Editor is the "Contents of 'SAS Environment'".
When the explorer window is selected, a tree hierarchy view can be toggled. There are several ways to do this. Here is one way:
Select the explorer window
View > Show Tree
Having to do this every time SAS is opened becomes a pain. After we clean up the library tree, we will automate this.
Remove any extraneous libraries
SAS loads a variety of libraries by default. These include WORK, SASHELP, and SASUSER, as well as others that are part of non-base products. In my case, the MAPS, MAPSGFK, and MAPSSAS libraries are also loaded (see above picture). As I never have used these (and likely never will), they only serve to clutter up my library directory. To remove these, one can edit their config file.
SAS implements a whole web of config files. On a Windows system, the likely relevant sasv9.cfg file is located here:
C:\Program Files\SASHome\SASFoundation\9.4\nls\en
You will need admin rights to edit it. Disregarding the DO NOT EDIT BELOW THIS LINE warning, comment out the the following using PL/I style comments.
Un-commented:
-MAPS !SASROOT\maps
-MAPSGFK !SASROOT\mapsgfk
-MAPSSAS !SASROOT\maps
Commented:
/* -MAPS !SASROOT\maps*/
/* -MAPSGFK !SASROOT\mapsgfk*/
/* -MAPSSAS !SASROOT\maps*/
Now when SAS opens, the MAPS, MAPSGFK, and MAPSSAS library will not be automatically loaded. Unfortunately, there does not seem to be a way to disable the loading of the SASUSER and SASHELP libraries. If someone knows how, please let me know!
Configure the Explorer Window
The explorer window can be 'configured' using the DM statement and the AUTOEXEC.sas facility.
Navigate to the directory containing SAS.EXE. On a default Windows installation, it is located here:
C:\Program Files\SASHome\SASFoundation\9.4
Create a SAS program named AUTOEXEC.sas containing the following code and place it in the directory which contains SAS.EXE. This step requires admin privileges. I find it easiest to create the file in a non-privileged environment and simply copy the AUTOEXEC.sas program into the directory.
Include this in the AUTOEXEC.sas program:
dm 'dmsexp; tree; expand libraries; expand work;';
When SAS intializes, the AUTOEXEC.sas code is executed before any user input is accepted. The above code does the following:
dmsexp - Brings the explorer window into command focus.
tree - Toggles the tree hierarchy view.
expand libraries - Within the "Active Libraries" pane, drills down into Libraries.
expand work - Within the "Active Libraries" pane, drills down into the Work library.
Each of these is a separate command and could be issued on separate lines. Instead of this, semi-colons are used to issue them in a single line.
Now when SAS is opened, the tree menu is available and the contents of the Work library are viewed. The picture below is somewhat deceiving. The "SAS Environment" pane is not set to a convenient width as pictured. It must be manually adjusted. If anyone has a way to automate this, please let me know!
Storing data sets in sub-folders
To ensure that data sets are deleted when the SAS session ends, sub-folders needs to be created within the temporary system folder where the Work library points to.
The following structure can now be followed:
/*Determine location of Work directory*/
%let dirWORK = %sysfunc(pathname(Work));
/*Allow LIBNAME statement to create new directories*/
options dlcreatedir;
/*Create sub-folders within the temporary Work directory
and assign librefs*/
libname raw "&dirWORK./raw";
libname interm "&dirWORK./intermediate";
libname results "&dirWORK./results";
Now, all the raw data sets can be assigned to the raw library. Within SAS, they will be logically separated from Work. That is, if the data set foobar is created in the raw library, it can only be accessed via raw.foobar. A statement such as data = foobar or data = work.foobar will not work. Yet because the raw library is in fact a sub-folder of Work, it will be deleted when the SAS session is ended.

Toad schema name in objects

In the Schema Browser, Toad automatically includes the schema name in the name of database objects. For example, when I click on a procedure to see it's source, it goes:
CREATE OR REPLACE PROCEDURE MY_USER.MY_PROCEDURE
Is there a way to disable this? Such that it shows
CREATE OR REPLACE PROCEDURE MY_PROCEDURE
This would make copying code and running it in other schema's a lot easier!
This is not intuitive at all, but the Schema Browser is using the Editor option to include schema names. See the Editor|Open/Save page in Options. Set the "Owner name" value accordingly in the "Object loading" group box.
Always include - always includes schema name
Never include - never includes schema name
Include on loads from other schemas - includes name when the object is not owned by the logged on schema

Calling webservice from voice xml

How I can call webservice from voice xml (vxml) document. I am using an opensource IVR project and I need to run a webservice for any given option from within the vxml document.
This is similar to this query;
how can I call a webservice from voiceXML?
However, solution is provided there but it is not
You cannot call a web service directly from a VoiceXML application. There are generally two approaches for getting data into a VoiceXML application:
Use the data element tag to make an http request. The result must be XML. You will need to parse the result with the provided DOM functions. Note, some browsers have extended features to facilitate XML parsing. This also requires a VoiceXML 2.1 compliant browser.
Transfer control to a dynamic bit of server code that returns VXML to be processed populating your desired variables. This can be done with a goto element or subdialog element.
Your question is incomplete, but I suspect I know what's bothering you.
I get information from a webservice by using
<data name="return_data" srcexpr="some_url" method="post" namelist="var1 var2 var3" />
The data I get back is inside the return_data variable. In my case, the data are in XML format, and I use JavaScript functions to extract the data I need.
As an aside, for maintainability, re-usability, and ease of reading, I personally find it useful to create separate files for the JS functions and include them via <script> into my root VoiceXML document.

List all available models in EMF application

I'm working on a project consisting of two Eclipse plugin projects. One is an EMF project and contains the metamodel for the application. The other one is the acctual plugin working on that metamodel.
I'm now looking for a way to list all types of models available in the metamodel project. Since I basically need all generated classes I could use reflections to iterate through the metamodel package but I'd prefer an easier way if there is one.
The models are already listed as extensions in the plugin.xml like this:
<plugin>
<extension point="org.eclipse.emf.ecore.generated_package">
<package
uri="MyModel"
class="org.myproject.metamodel.MyModel.MyModelPackage"
genModel="model/MetaModel.genmodel"/>
</extension>
</plugin>
where the class MyModelPackage extends EPackage and org.myproject.metamodel.MyModel also contains all the other generated classes I need to list. I'm guessing that I can use that information but I still don't know how.
Update
The project I'm working on is based on EMFStore. Running it offers the EMFStore perspective. If I have the Navigator view with a project I can right click on that project and select New Model Element. This opens a dialog where all the model elements from my metamodel are listed so it is possible. It must be done somewhere in EMFStore or one of it's dependencies. I looked through the source code but can't seem to find where it's done.
The plugin.xml of the project org.eclipse.emf.emfstore.perspective refers to the class org.eclipse.emf.emfstore.emfperspective.EMFStorePerspective which I can't find in the sources. I imported the project via the Eclipse Import Plug-Ins and Fragments functionality and it has no source folder. In the EMFStore git repositories I can't even find that project.
Update
I now got the registry that contains the generated packages using EPackage.Registry.INSTANCE. Unfortunately it contains more than the EPackages from the one project containing the metadata (org.myproject.metamodel). Now I'm just looking for a proper way to filter it, but still can't get the hang of it.
Update
As the filtering is not part of my original question I accepted the answer by #SpaceTrucker. For those who are curious, this is how I've done it now:
Registry registry = EPackage.Registry.INSTANCE;
for (String key : new HashSet<String>(registry.keySet())) {
EPackage ePackage = registry.getEPackage(key);
if (ePackage.getClass().getName().startsWith("org.myproject.metamodel")) {
//do stuf
}
}
I found no way to filter for the project but luckily all the packages start with the same prefix.
EPackages may be registered via an EPackage.Registry. There seems to be a globally used instance available via ECorePlugin.getDefaultRegistryImplementation(). However I'm not 100% sure on that.
MoDisco comes with a EMF Model Browser, where you are also able to select any registered EMF model. So you also could have a look at those sources.

Can YQL Open Data Tables make use of multiple URL fields that its XML scheme seems to support?

As I experiment more and more with making my own Open Data Tables for YQL I find what might be some gaps in the documentation. As I'm a hands-on learner and like to understand everything I use I probe these gaps to try to learn how everything works.
I've noticed that in the XML format for Open Data Tables, there is a <urls> "array" which usually contains just a single <url> element though sometimes there is no <url>. Here's the beginning of a typical ODT XML file:
<table xmlns="http://query.yahooapis.com/v1/schema/table.xsd" https="true">
<meta>
<author>Paul Donnelly</author>
<documentationURL>http://developer.netflix.com/docs/REST_API_Reference#0_52696</documentationURL>
</meta>
<bindings>
<select itemPath="" produces="XML">
<urls>
<url env="all">http://api.netflix.com/catalog/titles/</url>
</urls>
But I can't seem to find in the documentation whether it can ever contain more than one. I can't find any examples that do but when I try adding more than one everything works and no errors are thrown, though I also can't find any way to access the <url> elements beyond the first one.
Is there any use for the url/urls fields being an XML array? Is there any way to make use of more than one url here? Or is it just a quirk of the format that has no real reason?
Is there any use for the url/urls fields being an XML array?
Is there any way to make use of more than one url here?
The <url> elements can have an env attribute. This env attribute can contain all, prod, int, dev, stable, nightly, perf, qaperf, gamma or beta.
When the table is executed, the current environment (the YQL environment, not the more familiar environment file) is checked and the first matching <url> (if any) is used. If no matching env is found (and there is no all, which is pretty self-descriptive) then an error will be issued; for example, "Table not defined in this environment prod".
Note that for public-facing YQL, the environment is prod; only prod and all make sense to be used in your Open Data Tables.
Or is it just a quirk of the format that has no real reason?
Not at all.
I assume that this information is "missing" from the online documentation purely because it is only useful internally within Yahoo!, but equally it could just be another place where the docs are somewhat out-of-date.
Finally, none of the 1,100 or so Community Open Data Tables specify more than one <url>, and only a handful (55) make use of the env attribute (all using the value all).