XSLT select, problem with double namespace - xslt

when I use this xslt inline template on a BizTalk map
<xsl:template name="Test2">
<xsl:param name="sale" />
<xsl:variable name="promo" select="//s1:Sale[s1:ItemID = $sale]/s1:RetailPriceModifier[#MethodCode='Promotion' and #VoidFlag='false' and s1:ReasonCode= 'TRANSACTION_DISCOUNT']"/>
<DISCOUNT_VALUE1><xsl:value-of select="$promo[1]/s1:Amount"/></DISCOUNT_VALUE1>
<DISCOUNT_VALUE2><xsl:value-of select="$promo[2]/s1:Amount"/></DISCOUNT_VALUE2>
<DISCOUNT_VALUE3><xsl:value-of select="$promo[3]/s1:Amount"/></DISCOUNT_VALUE3>
<DISCOUNT_VALUE4><xsl:value-of select="$promo[4]/s1:Amount"/></DISCOUNT_VALUE4>
<DISCOUNT_VALUE5><xsl:value-of select="$promo[5]/s1:Amount"/></DISCOUNT_VALUE5>
<DISCOUNT_VALUE6><xsl:value-of select="$promo[6]/s1:Amount"/></DISCOUNT_VALUE6>
<DISCOUNT_REASON1><xsl:value-of select="$promo[1]/s1:dtv:DiscountReasonCode"/></DISCOUNT_REASON1>
<DISCOUNT_REASON2><xsl:value-of select="$promo[2]/s1:dtv:DiscountReasonCode"/></DISCOUNT_REASON2>
<DISCOUNT_REASON3><xsl:value-of select="$promo[3]/s1:dtv:DiscountReasonCode"/></DISCOUNT_REASON3>
<DISCOUNT_REASON4><xsl:value-of select="$promo[4]/s1:dtv:DiscountReasonCode"/></DISCOUNT_REASON4>
<DISCOUNT_REASON5><xsl:value-of select="$promo[5]/s1:dtv:DiscountReasonCode"/></DISCOUNT_REASON5>
<DISCOUNT_REASON6><xsl:value-of select="$promo[6]/s1:dtv:DiscountReasonCode"/></DISCOUNT_REASON6>
</xsl:template>
I receive the following error:
Expected end of the expression, found ':'.
$promo[1]/s1:dtv -->:<-- DiscountReasonCode
Could you please tell me how to resolve this issue?
here an input example:
<RetailPriceModifier MethodCode="Promotion" VoidFlag="false">
<SequenceNumber>1</SequenceNumber>
<Amount Action="Subtract">1.98</Amount>
<PromotionID>3705:8604:</PromotionID>
<ReasonCode>DEAL</ReasonCode>
</RetailPriceModifier>
<RetailPriceModifier MethodCode="Promotion" VoidFlag="false">
<SequenceNumber>2</SequenceNumber>
<Amount Action="Subtract">0.38</Amount>
<PromotionID>3706:8605:</PromotionID>
<ReasonCode>DEAL</ReasonCode>
</RetailPriceModifier>
<RetailPriceModifier MethodCode="Promotion" VoidFlag="false">
<SequenceNumber>3</SequenceNumber>
<Amount Action="Subtract">0.40</Amount>
<PromotionID>TRANS_PCT_PROMPT</PromotionID>
<ReasonCode>TRANSACTION_DISCOUNT</ReasonCode>
<dtv:DiscountReasonCode>DC4</dtv:DiscountReasonCode>
</RetailPriceModifier>
the output should be:
<DISCOUNT_VALUE1>0.40</DISCOUNT_VALUE1>
<DISCOUNT_REASON1>DC4</DISCOUNT_REASON1>
thanks and regards

The DiscountReasonCode elements are in the dtv namespace.
Remove the sv1: prefix from those XPaths targeting the DiscountReasonCode.
The XPath should be: $promo[1]/dtv:DiscountReasonCode

Related

Hot to access principalResult of the transformation? [saxonJS]

I migrate from saxon-CE to saxonJS (v1.2.0)
The output of the XSLT transformation need to be captured as an XML Document object as it was in saxon-CE:
var xslPath = './*.xsl';
var xsl = Saxon.requestXML(xslPath);
var proc = Saxon.newXSLT20Processor(xsl);
var xmlDoc;
var xmlDocTransformed;
var xmlStr;
xmlDoc = Saxon.parseXML(app.getLoadedMEI());
xmlDocTransformed = proc.transformToDocument(xmlDoc);
It tried to apply SaxonJS this way:
var result;
result = SaxonJS.transform({
stylesheetLocation: "./*.sef.xml",
sourceLocation: "./*.xml",
destination: "application"
});
and expected to get a transformation results object where I can access the principalResult property as described in the official documentation (#destination) and in this presentation.
When running the code I obtain the following:
There is no problem with transformation itself: when destination is set to replaceBody it works as expected.
Eventually I solved my task with the following code (Saxon JS 2.3):
var options = {
stylesheetLocation: xslPath,
sourceText: inputXmlStr,
stylesheetParams: params,
destination: "document"
};
var result = SaxonJS.transform(options);
var transformedXmlStr = SaxonJS.serialize(result.principalResult);
The SEF could be produced by xslt3 tool.
Note that you might use the alternative command for this (windows 10 power shell):
node node_modules/xslt3/xslt3.js "-t" "-xsl:stylesheet.xsl" "-export:stylesheet.sef.json" "-nogo"
One way is, of course, to use the fn:transform function with "normal" XSLT code:
const xml = `<root>
<item>a</item>
</root>`;
const xslt = `<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:output method="xml"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="/" name="xsl:initial-template">
<xsl:next-match/>
<xsl:comment>Run with {system-property('xsl:product-name')} {system-property('xsl:product-version')} {system-property('Q{http://saxon.sf.net/}platform')}</xsl:comment>
</xsl:template>
</xsl:stylesheet>`;
const resultString = SaxonJS.XPath.evaluate(`transform(map { 'source-node' : parse-xml($xml), 'stylesheet-text' : $xslt, 'delivery-format' : 'serialized' })?output`, null, { params : { 'xml' : xml, 'xslt' : xslt } });
console.log(resultString);
<script src="https://martin-honnen.github.io/Saxon-JS-2.3/SaxonJS2.js"></script>
Not recommended for performance reason but perhaps a workaround that avoid the hassle of creating an SEF. If you want to create an SEF, note, that the Node.js xslt3 tool from Saxonica can also do that, you don't need a current version of Saxon EE, just xslt3 -t -export:my-sheet.sef.json -nogo -xsl:my-sheet.xsl.

How to set language data with Saxon HE 10.2?

How can I set language data correctly with Saxon HE 10.2? I need the XSLT Processor to output the current date with a month name written out in German, like 21. Oktober 2020. Unfortunately, the processor outputs
[Language: en]21. October 2020.
Saxon PE gives the desired output out of the box.
This is my XSLT code:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="3.0">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:value-of select="format-dateTime(current-dateTime(), '[D]. [MNn] [Y]', 'de', (), ())"/>
</xsl:template>
</xsl:stylesheet>
The test XML source code file is like this:
<?xml version="1.0" encoding="UTF-8"?>
<root/>
In Linux, I run java -cp $xsltProc $class -s:source.xml -xsl:stylesheet.xslt -o:result.
$xsltProc is the path to the file saxon-he-10.2.jar.
$class is net.sf.saxon.Transform.
Any help would be greatly appreciated.
To support German date formats "out of the box", you need Saxon-PE or higher.
See https://saxonica.com/documentation/index.html#!extensibility/config-extend/localizing/other-numberings
If you want this with Saxon-HE, you can compile the open source code for class net.sf.saxon.option.local.Numberer_de and register it with the Configuration:
configuration.setLocalizerFactory(new LocalizerFactory() {
public Numberer getNumberer(String language, String country) {
if (lang.equals("de")) {
return new Numberer_de();
} else {
...
}
});
The Numberer code is available at https://saxonica.plan.io/projects/saxon/repository/he/revisions/master/entry/latest10/hej/net/sf/saxon/option/local/Numberer_de.java
I tried the following with the example files from the original question, but the Configuration was never invoked.
I presume the Configuration needs to be registered somehow?
final Configuration config = new Configuration();
/**/ config.setLocalizerFactory(new LocalizerFactory() {
public Numberer getNumberer(final String language, final String country) {
if (language.equals("de")) {
return Numberer_de.getInstance();
} else {
return null;
}
}
});
Transform.main(new String[] {
"-s:source.xml",
"-xsl:stylesheet.xslt",
"-o:result.txt"
});

Mapping unstructured schema elements into a structured

I just want to convert from this the hotel_info structure to the AvailableHotels structure: The hotel_info XML comes from a legacy SOAP web service and my goal is to the structure AvailableHotels ; The elements required from the hotel_info occur in various places
<hotel_info>
<AvailableHotels>
<hotel_1>
<hotelName_1>safd1</hotelName_1>
<booked_by>Taylor Volkes</booked_by>
<booking_id>sdf</booking_id>
</hotel_1>
<hotel_2>
<hotelName_1>safd2</hotelName_1>
<booked_by>Sam Volkes</booked_by>
<booking_id>sdf</booking_id>
</hotel_2>
</AvailableHotels>
<hotel_details>
<detail>
<hotelReference>hotel_1</hotelReference>
<reservation_complete>Yes</reservation_complete>
<hotelAddress1>sd</hotelAddress1>
<hotelAddress2>sd</hotelAddress2>
<hotelCity>sd</hotelCity>
<hotelState>sd</hotelCity>
<hotelState>AK</hotelState>
<suite_required>Yes</suite_required>
<email_provided>sdfeiwocmed</email_provided>
<hotelState__b_>HI</hotelState__b_>
</detail>
<detail>
<hotelReference>hotel_2</hotelReference>
<reservation_complete>Yes</reservation_complete>
<hotelAddress1>sd</hotelAddress1>
<hotelAddress2>sd</hotelAddress2>
<hotelCity>sd</hotelCity>
<hotelState>sd</hotelCity>
<hotelState>AK</hotelState>
<suite_required>Yes</suite_required>
<email_provided>sdfeiwocmed</email_provided>
<hotelState__b_>HI</hotelState__b_>
</detail>
</hotel_details>
<hotel_info>
To this:
<AvailableHotels>
<hotel>
<HotelName>hotel_1</HotelName>
<HotelAddressLine1Text></HotelAddressLine1Text>
<HotelAddressLine2Text></HotelAddressLine2Text>
<HotelCityName></HotelCityName>
<HotelStateCode></HotelStateCode>
<HotelZip5Code></HotelZip5Code>
<HotelZip4Code></HotelZip4Code>
<reservation_status>booked</reservation_status>
</hotel>
<hotel>
<HotelName>hotel_2</HotelName>
<HotelAddressLine1Text></HotelAddressLine1Text>
<HotelAddressLine2Text></HotelAddressLine2Text>
<HotelCityName></HotelCityName>
<HotelStateCode></HotelStateCode>
<HotelZip5Code></HotelZip5Code>
<reservation_status>booked</reservation_status>
<HotelZip4Code></HotelZip4Code>
</hotel>
</AvailableHotels>
How can I do this?
Step by step:
Create the output to render the AvailableHotels -hotel - HotelName part
create a variable curHotel with name() of the tags inside your AvailableHotels
use the parameter as selection criteria for apply-templates something along the lines of <xsl:apply-templates select="/hotel_info/hotel_details/detail[hotelReference=$curHotel]" />
(off my head, might contain typos)

Xpath matching expression gives two strings values

I have an requirement to extract below value.
<cidx:ReferenceInformation ReferenceType="DeliveryNoteNumber">
<cidx:DocumentReference>
<cidx:DocumentIdentifier>5004330471</cidx:DocumentIdentifier>
</cidx:DocumentReference>
</cidx:ReferenceInformation>
I am using the below Xpath expression and getting 2 values match.
Expression
/*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='ShipNotice']/*[local-name()='ShipNoticeBody']/*[local-name()='ShipNoticeProperties']/*[local-name()='ReferenceInformation']/*[local-name()='DocumentReference']/*[local-name()='DocumentIdentifier']/text()
Output
<?xml version="1.0" encoding="UTF-8"?>
<result>
5004330471
0803692106
</result>
I have tested the Xpath in the online tool
[http://www.xpathtester.com/xpath][1]
Below is INPUT XML
<SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP:Header/>
<SOAP:Body>
<cidx:ShipNotice xmlns:cidx="urn:cidx:names:specification:ces:schema:all:4:0" Version="4.0">
<cidx:Header>
<cidx:ThisDocumentIdentifier>
<cidx:DocumentIdentifier>0000001113658104</cidx:DocumentIdentifier>
</cidx:ThisDocumentIdentifier>
<cidx:ThisDocumentDateTime>
<cidx:DateTime DateTimeQualifier="On">2015-01-22T20:15:35Z</cidx:DateTime>
</cidx:ThisDocumentDateTime>
<cidx:From>
<cidx:PartnerInformation>
<cidx:PartnerName>MOS Company</cidx:PartnerName>
<cidx:PartnerIdentifier Agency="AGIIS-EBID">1234567890123</cidx:PartnerIdentifier>
<cidx:AddressInformation>
<cidx:AddressLine>N. Lindbergh</cidx:AddressLine>
<cidx:CityName>Columbia</cidx:CityName>
<cidx:StateOrProvince>MO</cidx:StateOrProvince>
<cidx:PostalCode>63190</cidx:PostalCode>
<cidx:PostalCountry>US</cidx:PostalCountry>
</cidx:AddressInformation>
</cidx:PartnerInformation>
</cidx:From>
<cidx:To>
<cidx:PartnerInformation>
<cidx:PartnerName> DIV BOWLNG GR VERA</cidx:PartnerName>
<cidx:PartnerIdentifier Agency="AssignedByPapiNet">0001664057</cidx:PartnerIdentifier>
<cidx:ContactInformation>
<cidx:ContactName>2015</cidx:ContactName>
<cidx:ContactDescription>SeedYear</cidx:ContactDescription>
</cidx:ContactInformation>
<cidx:ContactInformation>
<cidx:ContactName>1024122440000</cidx:ContactName>
<cidx:ContactDescription>AGIIS-EBID</cidx:ContactDescription>
</cidx:ContactInformation>
<cidx:AddressInformation>
<cidx:AddressLine>17410 PIKE 291</cidx:AddressLine>
<cidx:CityName>BOWLING GREEN</cidx:CityName>
<cidx:StateOrProvince>MO</cidx:StateOrProvince>
<cidx:PostalCode>633343045</cidx:PostalCode>
<cidx:PostalCountry>US</cidx:PostalCountry>
</cidx:AddressInformation>
</cidx:PartnerInformation>
</cidx:To>
</cidx:Header>
<cidx:ShipNoticeBody>
<cidx:ShipNoticeProperties>
<cidx:ShipmentIdentification>
<cidx:DocumentReference>
<cidx:DocumentIdentifier>0803692106</cidx:DocumentIdentifier>
</cidx:DocumentReference>
</cidx:ShipmentIdentification>
<cidx:ShipDate>
<cidx:DateTime DateTimeQualifier="On">2015-01-22T00:00:00Z</cidx:DateTime>
</cidx:ShipDate>
<cidx:PurchaseOrderInformation>
<cidx:DocumentReference>
<cidx:DocumentIdentifier>PO8956234</cidx:DocumentIdentifier>
<cidx:ReferenceItem>000530</cidx:ReferenceItem>
</cidx:DocumentReference>
</cidx:PurchaseOrderInformation>
<cidx:TransportMethodCode Domain="UN-Rec-19">3</cidx:TransportMethodCode>
<cidx:ReferenceInformation ReferenceType="DeliveryNoteNumber">
<cidx:DocumentReference>
<cidx:DocumentIdentifier>5004330471</cidx:DocumentIdentifier>
</cidx:DocumentReference>
</cidx:ReferenceInformation>
<cidx:ReferenceInformation ReferenceType="BillOfLadingNumber">
<cidx:DocumentReference>
<cidx:DocumentIdentifier>0803692106</cidx:DocumentIdentifier>
</cidx:DocumentReference>
</cidx:ReferenceInformation>
<cidx:ShipNoticeDate>
<cidx:DateTime DateTimeQualifier="On">2015-01-22T20:15:35Z</cidx:DateTime>
</cidx:ShipNoticeDate>
</cidx:ShipNoticeProperties>
</cidx:ShipNoticeBody>
</cidx:ShipNotice>
</SOAP:Body>
</SOAP:Envelope>
Can anyone please advise how to get only this value?
<cidx:DocumentIdentifier>5004330471</cidx:DocumentIdentifier>
Looks like you need to test the ReferenceType attribute in the cidx:ReferenceInformation element:
/*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='ShipNotice']/*[local-name()='ShipNoticeBody']/*[local-name()='ShipNoticeProperties']/*[local-name()='ReferenceInformation' and #ReferenceType='DeliveryNoteNumber']/*[local-name()='DocumentReference']/*[local-name()='DocumentIdentifier']
Note: This xpath can be cleaned up a lot if you can declare the namespaces and use prefixes in the path.
You could also clean it up using * for the prefix if you're using XPath 2.0...
/*:Envelope/*:Body/*:ShipNotice/*:ShipNoticeBody/*:ShipNoticeProperties/*:ReferenceInformation[#ReferenceType='DeliveryNoteNumber']/*:DocumentReference/*:DocumentIdentifier

Getting 'WrappedRuntimeException' when using XSL-FO in an Xpage

I am trying to create a PDF from the contents of an xpage. I am following the format that Paul Calhoun used in Notes in 9 #102. I am able to create PDF's for views, but having trouble creating one for a document. I do not think the error is in Paul's code so I am not including it here, although I can if need be.
To generate the XML to display I use the generateXML() method of the document class in java. I get a handle to the backend document and then return the XML. The XML appears well formed, the top level tab is <document>. I pass this XML to the transformer which is using Apache FOP. All of my code is contained in the beforeRenderResponse of an xAgent.
The XSL stylesheet that I am using is a stripped down version to just get a proof of concept to work. I am going to include it, because the problem likely resides with this code. I am totally new to XSL.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.1"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
exclude-result-prefixes="fo">
<xsl:output
method="xml"
version="1.0"
omit-xml-declaration="no"
indent="yes" />
<xsl:param
name="versionParam"
select="'1.0'" />
<xsl:template match="document">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master
master-name="outpage"
page-height="11in"
page-width="8.5in"
margin-top="1in"
margin-bottom="1in"
margin-left="1in"
margin-right="1in">
<fo:region-body />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4">
<fo:block
font-size="16pt"
font-weight="bold"
space-after="5mm">
Apache FOP Proof of Concept.
</fo:block>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
In the log file I get the message:
FATAL ERROR: 'com.ibm.xtq.common.utils.WrappedRuntimeException: D:\Program Files\IBM\Domino\<document form='PO'>
The error echos the entire XML in the log that it is trying to transform and ends with:
(The filename, directory name, or volume label syntax is incorrect.)'
Notice that Domino is trying to include the XML in a path. I know this is wrong, but don't know what to do to fix it.
EDIT: This is the Java class that runs the transformation. This code is from Paul Calhoun's demo.
import java.io.OutputStream;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
public class DominoXMLFO2PDF {
public static void getPDF(OutputStream pdfout,String xml,String xslt, Boolean authReq, String usernamepass) {
try {
//System.out.println("Transforming...");
Source xmlSource,xsltSource; //Source xmlSource = new StreamSource("http://localhost/APCC.nsf/Main?ReadViewEntries&count=999&ResortAscending=2");
xmlSource = new StreamSource(xml); //Source xsltSource = new StreamSource("http://localhost/APCC.nsf/viewdata.xsl");
xsltSource = new StreamSource(xslt);// configure fopFactory as desired
final FopFactory fopFactory = FopFactory.newInstance();
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
// configure foUserAgent as desired
// Setup output
// OutputStream out = pdfout;
// out = new java.io.BufferedOutputStream(out);
try {
// Construct fop with desired output format
Fop fop = fopFactory.newFop(org.apache.xmlgraphics.util.MimeConstants.MIME_PDF,foUserAgent, pdfout);
// Setup XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(xsltSource);
//transformer.setParameter("versionParam", "Company List"); // Set the value of a <param> in the stylesheet
Source src = xmlSource; // Setup input for XSLT transformation
Result res = new SAXResult(fop.getDefaultHandler()); // Resulting SAX events (the generated FO) must be piped through to FOP
transformer.transform(src, res); // Start XSLT transformation and FOP processing
} catch (Exception e) {
} finally {
}
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
This code is called in the xAgent using this line:
var retOutput = jce.getPDF(pageOutput, xmlsource, xsltsource, authReq, usernamepass);
The xmlsource is set with this line where the method returns XML using Document.generateXML():
var xmlsource = statusBean.generateXML(POdata, sessionScope.unidPDF);
Your problem is the XMLSource! When you look at Paul's code:
Source xmlSource = new StreamSource("http://localhost/APCC.nsf/Main?ReadViewEntries");
This points to an URL where to retrieve XML.On the other hand your code:
xmlsource = statusBean.generateXML(POdata, sessionScope.unidPDF);
contains the XML. So you need to change to:
String xmlstring = statusBean.generateXML(POdata, sessionScope.unidPDF);
Source xmlsource = new StreamSource(new java.io.StringReader(xmlstring));
I strongly suggest you try to keep all the Java in a java class, so you don't need to wrap/upwrap the objects in SSJS. Have a look at my series on FO too.