XRX/Metadata Shopper
From Wikibooks, the open-content textbooks collection
Contents |
[edit] Motivation
You want to allow non-programmers (Business Analysts, Project Managers, Business Units, Subject Matter Experts etc.) to be able to create a precise list of data elements from a metadata registry. This tool has a search function that allows these users to find data elements and then add them to a list that can be saved for future use. This list (called a wantlist) can then be used to generate sub-schemas that are imported into XML exchange documents.
Metadata shoppers are one of the key tools that allow non-programmers to create precise data exchange specifications. Anyone with a few hours of training can now create precise lists of data elements that will be semantically consistent with other data exchanges. In general shopping carts help the users find the "leaves" on the trees of a data exchange. The exact order of these elements, what elements are required, the nesting structure and the number of elements in an exchange are not usually considers part of the the metadata shopping process. These are considered "constraints" of the data exchange, not the semantics of the data exchange. The semantics is driven by the wantlist and the constraints are usually incorporated into and XML Schema of the exchange.
This pattern of separating the semantics of a data exchange from the constraints of an exchange is known as Separation of Concerns and is one of the principal forces that allow non-programmers to have increased participation in the creation of data exchanges processes.
[edit] Method
We will create a XForms application that has two "submission" elements. One that gets search results and the other that saves a wantlist. When a user sees a search result they want to keep it is added to the wantlist. At the end of the session a user typically saves their wantlist in a wantlist registry.
The wantlist created by this program is designed to be used by the subschema generator used later in this book.
[edit] Screen Images
Here is a sample screen image of a shopping cart before you begin searching for data elements:
Here is the result of putting a search term such as "last" in the search field and getting a single hit. After you get this hit you can click the add button and see the results get added to the wantlist on the right hand side.
Here is sample screen image after several metadata elements have been added to the shopping cart.
[edit] Data Element Search Results
The metadata shopper depends on a data element search service that will return a list of data elements that match a query.
For example if the URL of the data element query was the following:
BASENAME/search/search.xq?q=birth
The format of the result set would be the following:
<results>
<DataElement>
<DataElementName>PersonBirthDate</DataElementName>
<NamespaceURI>http://www.example.com/registry<NamespaceURI>
<DataElementDefinitionText>The date a person was born.</DataElementDefinitionText>
</DataElement>
<DataElement>
<DataElementName>PersonGivenName</DataElementName>
<NamespaceURI>http://www.example.com/registry<NamespaceURI>
<DataElementDefinitionText>The name given to a person at birth. Also referred to as a first name in western cultures.</DataElementDefinitionText>
</DataElement>
</results>
After a search submission is sent to the server, the search result come back and automatically populate the search results instance in the form. This is done without the form reloading.
[edit] Program Source
The following XQuery dynamically generates an XForms application. We use XQuery to generate the form since we will frequently want to parameterize in with a default wantlist.
xquery version "1.0"; declare option exist:serialize "method=xml media-type=text/xml indent=yes"; let $title := 'Basic Metadata Shopper Version 1' return <html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events"> <head> <title>{$title}</title> <link rel="stylesheet" type="text/css" href="shopping-cart.css"/> <xf:model> <!-- here is where you store the search query before you hit the "search button". --> <xf:instance xmlns="" id="search-criteria"> <data> <q/> </data> </xf:instance> <xf:instance xmlns="" id="shopping-cart"> <data> <FileName>test.xml</FileName> <!-- Thing from the OWN namespace --> <DataElement> <DataElementName>Thing</DataElementName> <NamespaceURI>http://www.w3.org/2002/07/owl</NamespaceURI> <definition>The root of all data elements.</definition> </DataElement> </data> </xf:instance> <xf:instance xmlns="" id="search-response"> <data/> </xf:instance> <xf:instance xmlns="" id="save-wantlist-response"> <data/> </xf:instance> <xf:submission id="search" ref="instance('search-criteria')" method="get" action="search-elements.xq" replace="instance" instance="search-response" separator="&"> <xf:toggle case="case-busy" ev:event="xforms-submit"/> <xf:toggle case="case-submit-error" ev:event="xforms-submit-error"/> <xf:toggle case="case-done" ev:event="xforms-submit-done"/> </xf:submission> <xf:submission id="save-wantlist" ref="instance('shopping-cart')" method="post" action="../edit/save-new.xq" replace="instance" instance="save-wantlist-response" separator="&"> <xf:toggle case="save-wantlist-case-busy" ev:event="xforms-submit"/> <xf:toggle case="save-wantlist-case-submit-error" ev:event="xforms-submit-error"/> <xf:toggle case="save-wantlist-case-done" ev:event="xforms-submit-done"/> </xf:submission> <!-- just for testing if you don't have an instance inspector in the browser like XForms buddy --> <xf:submission id="echo-search-criteria" ref="instance('search-criteria')" method="post" action="../xqueries/echo-test.xq" replace="all"/> <xf:submission id="echo-wantlist" ref="instance('shopping-cart')" method="post" action="../xqueries/echo-test.xq" replace="all"/> </xf:model> </head> <body> <a class="breadcrumb" href="../index.xhtml">Metadata Registry Home</a> > <a class="breadcrumb" href="index.xhtml">Shopping Cart Home</a> <div class="search"> <h1>Metadata Shopper</h1> <xf:input ref="instance('search-criteria')/string" incremental="true"> <xf:label>Search:</xf:label> </xf:input> <xf:submit submission="search"> <xf:label>Search</xf:label> </xf:submit> <xf:switch> <xf:case id="ready"> <!-- <xf:submit submission="echo-search-criteria"> <xf:label>Echo Search Criteria</xf:label> </xf:submit> --> </xf:case> <xf:case id="case-busy"> <p>Waiting for response...</p> </xf:case> <xf:case id="case-submit-error"> <p>The server has returned a submit error event.</p> </xf:case> <xf:case id="case-done"> <div class="search-results"> <h3>Search Results:</h3> <xf:repeat id="search-results-repeat" nodeset="instance('search-response')/DataElement"> <div class="result"> <xf:trigger> <xf:label>Add</xf:label> <xf:action ev:event="DOMActivate"> <xf:insert nodeset="instance('shopping-cart')/DataElement" at="last()" position="after"/> <!-- the nth one selected --> <xf:setvalue ref="instance('debug')/search-index" value="index('search-results-repeat')"/> <xf:setvalue ref="instance('debug')/item-to-add" value="instance('search-response')/DataElement[index('search-results-repeat')=position()]/DataElementName"/> <!-- set the last element in the cart to the selected item --> <xf:setvalue ref="instance('shopping-cart')/DataElement[last()]/DataElementName" value="instance('search-response')/DataElement[index('search-results-repeat')=position()]/DataElementName"/> </xf:action> </xf:trigger> <div class="result-text"> <b> <xf:output ref="DataElementName"/> </b> <i> <xf:output ref="DataElementDefinitionText/text()"/> </i> </div> </div> </xf:repeat> </div> </xf:case> </xf:switch> <xf:switch> <xf:case id="ready"/> <xf:case id="save-wantlist-case-busy"> <p>Waiting for response...</p> </xf:case> <xf:case id="save-wantlist-case-submit-error"> <p>The server has returned a submit error event.</p> </xf:case> <xf:case id="save-wantlist-case-done"> <div class="search-results"> <xf:repeat id="search-results-repeat" nodeset="instance('save-wantlist-response')/results"> <xf:output ref="Message/text()"/> </xf:repeat> </div> </xf:case> </xf:switch> </div> <div class="shopping-cart-sidebar"> <img src="shopping-cart.jpg" height="50"/> <h3>Shopping Cart Contents:</h3> <ul> <xf:repeat id="shopping-cart-repeat" nodeset="instance('shopping-cart')/DataElement"> <li> <xf:output value="concat(prefix,':', DataElementName)" class="url"/> <!-- TODO figure out how to bind an output to a URL<xf:output value="concat( 'http://dlficsb501:8080/exist/rest/db/mdr/data-elements/views/view-data-element.xq?id=', DataElementName, prefix,':', DataElementName )" class="url" /> --> </li> </xf:repeat> <br/> <xf:input ref="instance('shopping-cart')/FileName"> <xf:label><b>Wantlist name:</b></xf:label> </xf:input> <xf:submit submission="save-wantlist"> <xf:label>Save Wantlist</xf:label> </xf:submit> <!-- <xf:submit submission="echo-wantlist"> <xf:label>Echo Wantlist</xf:label> </xf:submit> --> </ul> </div> </body> </html>
[edit] Discussion
You may also want to copy more that a single element into the shopping cart such as a book title and the price of the book. To do this you can use the new "origin" attribute of the XForms insert to copy on just a single element but an entire complex node into the shopping cart.


