XSLT to Concatenate Empty Values - xslt

We have a requirement that requires us to list out all the empty values from the incoming xml. I have searched but all I could find was listing non-null values, trying to use that for our xml is not returning the required results.
Here is the xml that we will receive and I want to be able to concatenate all the null values from this xml and print. Kindly assist.
<?xml version = "1.0" encoding = "UTF-8"?>
<Output>
<Rows>
<ns0:I2NA xmlns:ns0 = "http://www.example.com/schemas/Schema.xsd">
<ns0:Organization>108</ns0:Organization>
<ns0:AccountNumber>1231231231231231233 </ns0:AccountNumber>
<ns0:Status>0</ns0:Status>
<ns0:VipStatus>0</ns0:VipStatus>
<ns0:TypeOfIdNo>1</ns0:TypeOfIdNo>
<ns0:IdNo>2303111450 </ns0:IdNo>
<ns0:HomePhone>123456 </ns0:HomePhone>
<ns0:Employer> </ns0:Employer>
<ns0:EmployersPhone>123456 </ns0:EmployersPhone>
<ns0:FaxPhone>123456 </ns0:FaxPhone>
<ns0:MobileNo>0568520421 </ns0:MobileNo>
<ns0:CountryCode> </ns0:CountryCode>
<ns0:PostalCode> </ns0:PostalCode>
<ns0:Position> </ns0:Position>
<ns0:MaritalStatus>0</ns0:MaritalStatus>
<ns0:DateOfBirth>00000000</ns0:DateOfBirth>
<ns0:EmailAddrs> </ns0:EmailAddrs>
<ns0:UserCode1> </ns0:UserCode1>
<ns0:NationalityCode> </ns0:NationalityCode>
<ns0:NameLine1>ABC </ns0:NameLine1>
<ns0:NameLine2> </ns0:NameLine2>
<ns0:NameLine3> </ns0:NameLine3>
<ns0:ChDob> </ns0:ChDob>
<ns0:AddressLine1>USA </ns0:AddressLine1>
<ns0:AddressLine2>USA </ns0:AddressLine2>
<ns0:AddressLine3>USA </ns0:AddressLine3>
<ns0:AddressLine4>USA </ns0:AddressLine4>
<ns0:City> </ns0:City>
<ns0:State> </ns0:State>
<ns0:GenderCode>0</ns0:GenderCode>
<ns0:StatementNotifIndi> </ns0:StatementNotifIndi>
<ns0:Nationality> </ns0:Nationality>
<ns0:County> </ns0:County>
<ns0:LastName>John </ns0:LastName>
<ns0:MiddleName> </ns0:MiddleName>
<ns0:FirstName>SHAN MATHEW </ns0:FirstName>
<ns0:LangPref> </ns0:LangPref>
</ns0:I2NA>
</Rows>
<EOF>true</EOF>
When the XSLT is applied, we would like to receive the below string as output.
Status,Employer,CountryCode,PostalCode,Position,EmailAddrs,UserCode1,NationalityCode,NameLine2,NameLine3,ChDob,City,State,StatementNotifIndi,Nationality,County,MiddleName,LangPref
Thanks!

Use <xsl:value-of select="//*[not(*) and not(normalize-space())]/local-name()" separator=","/>. But I don't understand why your sample string starts with Status while the XML has a value <ns0:Status>0</ns0:Status> for that field.
With XSLT 1.0 you need a bit of more code:
<xsl:for-each select="//*[not(*) and not(normalize-space())]">
<xsl:if test="position() > 1"><xsl:text>.</xsl:text></xsl:if>
<xsl:value-of select="local-name()"/>
</xsl:for-each>

Related

disable-output-escaping="yes" is not working

I have the following code
<db:P_RECEIVED_XML>
<xsl:value-of disable-output-escaping="yes" select="oraext:get-content-as-string(/ns0:ReceivedMessage/MessageContent/*)"/>
</db:P_RECEIVED_XML>
when i test this transformation, by giving the value as
<MessageContent xmlns="">
<any_0 xmlns="##any">
<note>
<name>GENERAL</name>
<value><![CDATA[test ~<!##$%^&*()_~!##$%^&*()_+]]></value>
</note>
</any_0>
</MessageContent>
the output rendered is
<db:P_RECEIVED_XML><any_0 xmlns="##any">
<note>
<name>GENERAL</name>
<value>test ~<!##$%^&*()_~!##$%^&*()_+</value>
</note>
</any_0>
</db:P_RECEIVED_XML>
Here & is converted to & though i have used disable-output-escaping="yes".
Kindly help.
You have tagged your question as XSLT. In XSLT, using:
<xsl:value-of select="your-node-here" disable-output-escaping="yes" />
would have disabled the escaping, and not output & as &.
If you are seeing a different result, it's probably a result of your using an extension oraext:get-content-as-string() function. Try removing it and see what you get.
disable-output-escaping only works if the result tree produced by the XSLT processor is immediately serialized, and if the serialization is under the control of the the XSLT processor. That means, for example, that it doesn't work if the result is written to a DOM tree, and you then use the DOM serialization to produce lexical XML.
XSLT processors are allowed to ignore disable-output-escaping entirely.
So it basically depends on what XSLT processor you are using and how you are running it.

How to trim the XSLT use attribute expression

I am new to XSLT and I have got a special requirement. My XML file looks like below.
<results>
<result>
<Price>
<LinePrices>
<ProductId>ProductId:1000</ProductId>
<Uom>KG</Uom>
<Quantity>0</Quantity>
</LinePrices>
<LinePrices>
<ProductId>ProductId:1002</ProductId>
<Uom>EACH</Uom>
<Quantity>0</Quantity>
</LinePrices>
</Price>
</result>
<result>
<productlist>
<productid>1000</productid>
<relevance>0.9</relevance>
<sponsored>0</sponsored>
</productlist>
<productlist>
<productid>1001</productid>
<relevance>0.8</relevance>
<sponsored>0</sponsored>
</productlist>
</result>
</results>
I have to write XSLT keys to match the pattern. I have written the key for productlist as shown below.
<xsl:key name="productsIdForProduct" match="productlist" use="productid" />
In the similar way I am trying to write the key for LinePrices as shown below.
<xsl:key name="productsIdPrice" match="result/LinePrices" use="ProductId" />
However this returns 'ProductId:1000' in use attribute. I am trying to trim 'ProductId:' from the use attribute value. How can I write a trim expression to extract '1000' from 'ProductId:1000' inside XPATH expression?
Just use substring-after():
substring-after(ProductId,':')

XPath selector not working during PDF transformation

I have a DITA bookmap where I am storing image paths:
<bookmap>
<bookmeta>
<data id="productLogo">
<image href="images/_notrans/frontcover/productLogo.svg" />
</data>
<data id="productPhoto" >
<image href="images/_notrans/frontcover/productPhoto.jpg" />
</data>
</bookmeta>
</bookmap>
Then I attempt to grab the href values by data[#id]:
<xsl:variable name="productLogo"><xsl:value-of select="//data[#id='productLogo']/image/#href" /></xsl:variable>
<xsl:variable name="productPhoto"><xsl:value-of select="//data[#id='productPhoto']/image/#href" /></xsl:variable>
(These XPath expressions match the href when I test against my bookmap in Oxygen.)
During transformation I output:
<xsl:message>productPhoto: <xsl:value-of select="$productPhoto"/></xsl:message>
The value-of is always empty.
However, everything works as expected if I replace the id attribute with numbers:
<xsl:variable name="productLogo"><xsl:value-of select="//data[1]/image/#href" /></xsl:variable>
<xsl:variable name="productPhoto"><xsl:value-of select="//data[2]/image/#href" /></xsl:variable>
What am I doing wrong that's preventing using #id="whatever"?
The XSLT is not applied directly over the Bookmap contents, it is applied over an XML document which contains the bookmap with all topic references expanded in it and with some preprocessing applied to it.
If you set the "clean.temp" parameter to "no" you will find in the temporary files folder a file called something like "mapName_MERGED.xml", that is the XML document over which the XSLT is applied and as you will see in it, all IDs have been changed to be unique in the context of the entire XML document.
When usually working with data elements you should set the #name attribute to them like:
<data name="productLogo">
and match that name in the XSLT code.
There are examples of using "data" in the DITA 1.2 specs as well:
http://docs.oasis-open.org/dita/v1.2/os/spec/langref/data.html#data
Another option, depending on your needs, is to develop a naming convention for the product photos and use the element to build the URI. As the product logo shouldn't change for a product family, it wouldn't hurt to hard-code that in the XSLT code.

Retrieving sub-element attribute's value based on uniq-key with xslt ant

My xml looks something like this:
<someRoot
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../my.xsd">
<position name="quality">
<db>
<server name="blah-blah" type="xyz"/>
</db>
<some-more-element value="12345"/>
<my-needy-element>
<my-needy-sub-element name="uk1"
value="a,b,c"
more-attr="some-val"/>
<my-needy-sub-element name="uk2"
value="x,b,y,c"
more-attr="some-diff-val"/>
</my-needy-element>
</position>
</someRoot>
Retrieving say my single db-server name works after I do xmlproperty & samy something like : ${db.server(name)}. Now I am trying to retrieve value for sub elements - but it always
gives me all row values matching it. eg: ${my-needy-element.my-needy-sub-element(more-attr)} will print some-val,some-diff-val . How do I get attribute value matching
to paricular unique name , something like {my-needy-element.my-needy-sub-element(more-attr) with name="uk1"}
Adding editing comment: Is there any way even if I use xslt ant-task by passing 'uk1' & get required sub-element attribute value? with xsl:if or key match
Amending more:
Have tried with xsl & then an xslt ant , but it doesnot seem to give what I am looking for:
<xsl:template match="/someRoot/my-needy-element/my-needy-sub-element">
<someRoot>
<xsl:key name="my-needy-sub-element" match="text()" use="#name"/>
<xsl:apply-templates select="key('name',$xslParamPassed)"/>
</someRoot>
</xsl:template>
thanks,
You can't do this with xmlproperty but you might consider the third-party xmltask which lets you use full-fledged XPath expressions:
<xmltask source="file.xml">
<copy path="/someRoot/position/my-needy-element/my-needy-sub-element[#name='uk1']/#more-attr"
property="more.attr" />
</xmltask>
<echo>${more.attr}</echo>

Xslt transform on special characters

I have an XML document that needs to pass text inside an element with an '&' in it.
This is called from .NET to a Web Service and comes over the wire with the correct encoding &
e.g.
T&O
I then need to use XSLT to create a transform but need to query SQL server through a SP without the encoding on the Ampersand e.g T&O would go to the DB.
(Note this all has to be done through XSLT, I do have the choice to use .NET encoding at this point)
Anyone have any idea how to do this from XSLT?
Note my XSLT knowledge isn’t the best to say the least!
Cheers
<xsl:text disable-output-escaping="yes">&<!--&--></xsl:text>
More info at: http://www.w3schools.com/xsl/el_text.asp
If you have the choice to use .NET you can convert between an HTML-encoded and regular string using (this code requires a reference to System.Web):
string htmlEncodedText = System.Web.HttpUtility.HtmlEncode("T&O");
string text = System.Web.HttpUtility.HtmlDecode(htmlEncodedText);
Update
Since you need to do this in plain XSLT you can use xsl:value-of to decode the HTML encoding:
<xsl:variable name="test">
<xsl:value-of select="'T&O'"/>
</xsl:variable>
The variable string($test) will have the value T&O. You can pass this variable as an argument to your extension function then.
Supposing your XML looks like this:
<root>T&O</root>
you can use this XSLT snippet to get the text out of it:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:template match="root"> <!-- Select the root element... -->
<xsl:value-of select="." /> <!-- ...and extract all text from it -->
</xsl:template>
</xsl:stylesheet>
Output (from Saxon 9, that is):
T&O
The point is the <xsl:output/> element. The defauklt would be to output XML, where the ampersand would still be encoded.