I've been struggling with this for the last 2 days. I'm nowhere as familiar with XPATH and XSLT as I need to be, but time has not been conducive to truly dig in and study. This is being used in BMC's TrueSight Orchestration application, and as such is limited to using XPATH/XSLT 1.0.
Some add-on questions that I wouldn't mind being redirected to resources for explanations:
- I'm not familiar with an "identity template" and I have seen it referred to in several posts.
- I'm not familiar with templates with regard to how to be more selective of the elements, nodes, and node sets for processing.
- I'm a shell script programmer by experience, so a top-down approach is a bit foreign to me as it relates to how XML documents are processed.
- I'm still learning a lot of the terms, axes, relational paths vs. absolute paths, etc. when it comes to XPATH. I'm not afraid of "Googling" for answers, but sometimes having a go-to resource is better than trying to guess at what keywords might provide a result set that may lead to an answer.
- Is there a more recommended go-to resource? (I know that this is a loaded and biased question, but I'm expecting that there will be a handful of resources that will be more recommended than others.)
I have the following input document:
<servers>
<server os="WINDOWS" role="CENTRAL" account="*****" name="SERVP0001">
<services>
<service name="QlikLoggingService" start_type="AUTOMATIC" state="RUNNING">Qlik Logging Service</service>
<service name="QlikSenseEngineService" start_type="AUTOMATIC" state="RUNNING">Qlik Sense Engine Service</service>
<service name="QlikSensePrintingService" start_type="AUTOMATIC" state="RUNNING">Qlik Sense Printing Service</service>
<service name="QlikSenseProxyService" start_type="AUTOMATIC" state="RUNNING">Qlik Sense Proxy Service</service>
<service name="QlikSenseRepositoryDatabase" start_type="AUTOMATIC" state="RUNNING">Qlik Sense Repository Database</service>
<service name="QlikSenseRepositoryService" start_type="AUTOMATIC" state="RUNNING">Qlik Sense Repository Service</service>
<service name="QlikSenseSchedulerService" start_type="AUTOMATIC" state="RUNNING">Qlik Sense Scheduler Service</service>
<service name="QlikSenseServiceDispatcher" start_type="AUTOMATIC" state="RUNNING">Qlik Sense Service Dispatcher</service>
</services>
</server>
<server os="WINDOWS" role="SLAVE" account="*****" name="SERVP0002">
<services>
<service name="QlikLoggingService" start_type="AUTOMATIC" state="RUNNING">Qlik Logging Service</service>
<service name="QlikSenseEngineService" start_type="AUTOMATIC" state="RUNNING">Qlik Sense Engine Service</service>
<service name="QlikSensePrintingService" start_type="AUTOMATIC" state="RUNNING">Qlik Sense Printing Service</service>
<service name="QlikSenseProxyService" start_type="AUTOMATIC" state="RUNNING">Qlik Sense Proxy Service</service>
<service name="QlikSenseRepositoryService" start_type="AUTOMATIC" state="RUNNING">Qlik Sense Repository Service</service>
<service name="QlikSenseSchedulerService" start_type="AUTOMATIC" state="RUNNING">Qlik Sense Scheduler Service</service>
<service name="QlikSenseServiceDispatcher" start_type="AUTOMATIC" state="RUNNING">Qlik Sense Service Dispatcher</service>
</services>
</server>
<server os="WINDOWS" role="NPRINTING" account="*****" name="SERVN0001">
<services>
<service name="QlikNPrintingEngine" start_type="AUTOMATIC" state="RUNNING">Qlik NPrinting Engine</service>
<service name="QlikNPrintingLicenseService" start_type="AUTOMATIC" state="RUNNING">Qlik NPrinting License Service</service>
<service name="QlikNPrintingMessagingService" start_type="AUTOMATIC" state="RUNNING">QlikNPrintingMessagingService</service>
<service name="QlikNPrintingRepoService" start_type="AUTOMATIC" state="RUNNING">QlikNPrintingRepoService</service>
<service name="QlikNPrintingScheduler" start_type="AUTOMATIC" state="RUNNING">Qlik NPrinting Scheduler</service>
<service name="QlikNPrintingWebEngine" start_type="AUTOMATIC" state="RUNNING">Qlik NPrinting Web Engine</service>
</services>
</server>
</servers>
I am trying to select from the root element down, including only those service nodes that match either the @name attribute or the text value.
This is the XSL that I've been able to cobble together through several hours of searching and trial and error. The only part I have not been able to figure out is how to prevent the printing of the server node and its descendants when no matching service is found.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="no" />
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<xsl:template match="service">
<xsl:choose>
<xsl:when test="contains( translate( normalize-space( ./@name ), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ), translate( normalize-space( "${SERVICENAME}" ), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ) )">
<xsl:copy-of select="." />
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
This is the current output I'm getting with my XSL:
<servers>
<server os="WINDOWS" role="CENTRAL" account="*****" name="SERVP0001">
<services>
<service name="QlikLoggingService" start_type="AUTOMATIC" state="RUNNING">Qlik Logging Service</service>
</services>
</server>
<server os="WINDOWS" role="SLAVE" account="*****" name="SERVP0002">
<services>
<service name="QlikLoggingService" start_type="AUTOMATIC" state="RUNNING">Qlik Logging Service</service>
</services>
</server>
<server os="WINDOWS" role="NPRINTING" account="*****" name="SERVN0001">
<services />
</server>
</servers>
This is my desired output:
<servers>
<server os="WINDOWS" role="CENTRAL" account="*****" name="SERVP0001">
<services>
<service name="QlikLoggingService" start_type="AUTOMATIC" state="RUNNING">Qlik Logging Service</service>
</services>
</server>
<server os="WINDOWS" role="SLAVE" account="*****" name="SERVP0002">
<services>
<service name="QlikLoggingService" start_type="AUTOMATIC" state="RUNNING">Qlik Logging Service</service>
</services>
</server>
</servers>
In some cases, there may be more than one matching service for a server. For example, if I used "engine" as a keyword to match services, I would have 1 match in SERVP0001, 1 match in SERVP0002, and 2 matches in SERVN0001. My provided example output is using the keyword "logging" to match services.
I know that I do not have a template or Choose-When element that searches for and returns the services whose text values contain my search string. I figured that if I could get the attribute search to return the correctly formatted document, I could modify to suit for the service text.
Thank you in advance for whatever help and resources you can provide.
A simpler / shorter solution (no need to set something to 1 to remember there was a hit):
When this transformation is applied on the provided XML document (re-formatted to avoid the need for horizontal scrolling):
the wanted, correct result is produced:
If we change
<xsl:param name="pKeyword" select="'logging'"/>
to<xsl:param name="pKeyword" select="'engine'"/>
and run the transformation, again the expected correct result is produced: