I have an XML source that puts data at various "parent" levels. If I select the "detail" level, the parent attributes are not represented in the XML data feed. Is there some way to do that?
An example document:
<?xml version="1.0" encoding="UTF-8" ?> <services> <service name="V_ShippingInfo" owner="Douglas Kelly" userVer="1.0"> <consumer consName="Consumer_Shipping"> <details> <totalhits>1</totalhits> <successHits>1</successHits> <avgRespTime>1441</avgRespTime> <requestPayload>66</requestPayload> <responsePayload>625</responsePayload> </details> </consumer> </service> <service name="V_EmployeeData" owner="Douglas Kelly" userVer="1.0"></service> <service name="V_LocationSessionData" owner="INTERNAL\Administrator" userVer="1.0"> <consumer consName="Consumer_Vendor"> <details> <totalhits>1</totalhits> <successHits>1</successHits> <avgRespTime>1043</avgRespTime> <requestPayload>2258</requestPayload> <responsePayload>850</responsePayload> </details> </consumer> </service> <service name="V_CrmLocationUpdate" owner="Douglas Kelly" userVer="1.0"> <consumer consName="Consumer_ESB"> <details> <totalhits>24</totalhits> <successHits>0</successHits> <avgRespTime></avgRespTime> <requestPayload></requestPayload> <responsePayload></responsePayload> </details> </consumer> <consumer consName="unknown"> <details> <totalhits>4</totalhits> <successHits>0</successHits> <avgRespTime></avgRespTime> <requestPayload></requestPayload> <responsePayload></responsePayload> </details> </consumer> </service> <service name="V_CrmLocationDetailsUpdate" owner="Douglas Kelly" userVer="1.0"></service> <service name="V_CrmScheduleUpdate" owner="Douglas Kelly" userVer="1.0"></service> <service name="V_LocationMaster" owner="Douglas Kelly" userVer="1.1"> <consumer consName="Consumer_CRM"> <details> <totalhits>250</totalhits> <successHits>239</successHits> <avgRespTime>810</avgRespTime> <requestPayload>2276</requestPayload> <responsePayload>4327</responsePayload> </details> </consumer> </service> </services>I have "/services/service/consumer" as the repeat element, which brings in "consName" as a column, but not /service/@name nor /service/@owner. If I make /services/service the repeat element, then when there is more than one /services/service/consumer for a /services/service node, I get totalhits columns and totalhits_0 columns. Any ideas on how to get @name, @owner, @userVer in as columns, along with the consumer/details?
The repeating element here is not clear - normally you would expect it to be "//service", which gives you all the services as result. If all you are interested in are the services and their attributes, you could use "//service" as repeating element and simply specify that no children of that node should be processed.
Of course this throws away a lot of the data contained in the XML, so that's probably not want you want. The problem here is that each repeating element contains 0 to n child elements - and since each repeating element results in a single MashZone table row, the multiple children have to be put somewhere within that row. MashZone does this by creating additional columns and numbering them (that's why you get those "_0" columns). All data is then contained in the row - though not really usable.
Another approach, which is more complex but also more powerful, is to use the "preprocessing" feature of the XML operator. Essentially, you write a XSLT script that transforms your source XML so that it presents its data in a more MashZone-friendly format. The idea is to iterate over the "consumer" elements and enrich them with the information of their parent elements.
The XSLT script required looks complex but is rather simple for your sample. It restructures the XML so that the column names are a bit different, but makes all the information accessible for MashZone (I'm no real XSLT specialist, so there may be a shorter, more elegant version to achieve this).
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <!-- iterate over the services --> <xsl:template match="/"> <xsl:element name="result"> <xsl:for-each select="/services"> <xsl:apply-templates/> </xsl:for-each> </xsl:element> </xsl:template> <!-- simply copy all information of the consumers and their details --> <xsl:template match="text()|details|totalhits|successHits|avgRespTime|requestPayload|responsePayload"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template> <!-- enrich the consumers with their parents' information --> <xsl:template match="consumer"> <xsl:copy> <consName> <xsl:value-of select="@consName"/> </consName> <serviceOwner> <xsl:value-of select="../@owner"/> </serviceOwner> <serviceName> <xsl:value-of select="../@name"/> </serviceName> <serviceUserVer> <xsl:value-of select="../@userVer"/> </serviceUserVer> <xsl:apply-templates/> </xsl:copy> </xsl:template> <!-- add those cases where the service has no consumer --> <xsl:template match="service[not(consumer)]"> <consumer> <consName> </consName> <serviceOwner> <xsl:value-of select="@owner"/> </serviceOwner> <serviceName> <xsl:value-of select="@name"/> </serviceName> <serviceUserVer> <xsl:value-of select="@userVer"/> </serviceUserVer> </consumer> </xsl:template> </xsl:stylesheet>
If you add that XSLT script to the XML operator in the "preprocessing" option, and specify the new repeating element "consumer", the output will look like this:
As you see, nothing is impossible in MashZone...
ok, I was wondering if XSLT was the appropriate approach. (I updated my post - the selection I was using was /services/service/consumer - not /services/service/details). Since I mange the XML source (it is from an XQuery against CentraSite), I could also flatten the structure from there.