Set 1:
<?xml version='1.0' encoding='UTF-8'?>
<aa:Details xmlns:aa="urn:com.report">
<aa:Row>
<aa:Place>AAA</aa:Place>
<aa:PlaceID>A123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>BBB</aa:Place>
<aa:PlaceID>B123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>CCC</aa:Place>
<aa:PlaceID>C123</aa:PlaceID>
</aa:Row>
</aa:Details>
Set 2
<?xml version='1.0' encoding='UTF-8'?>
<aa:Details xmlns:aa="urn:com.report">
<aa:Row>
<aa:Place>AAA</aa:Place>
<aa:PlaceID>A123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>EEE</aa:Place>
<aa:PlaceID>E123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>FFF</aa:Place>
<aa:PlaceID>F123</aa:PlaceID>
</aa:Row>
</aa:Details>
I have two sets of data above coming from different sources.
I will be combining two sets of data as below
<?xml version='1.0' encoding='UTF-8'?>
<aa:Details xmlns:aa="urn:com.report">
<aa:Row>
<aa:Place>AAA</aa:Place>
<aa:PlaceID>A123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>BBB</aa:Place>
<aa:PlaceID>B123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>CCC</aa:Place>
<aa:PlaceID>C123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>AAA</aa:Place>
<aa:PlaceID>A123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>EEE</aa:Place>
<aa:PlaceID>E123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>FFF</aa:Place>
<aa:PlaceID>F123</aa:PlaceID>
</aa:Row>
</aa:Details>
I would like to transform and get below desired output based on below condition
The result of the output should be from Set 2 by removing any node when PlaceID value from Set 2 is equal to Set 1
Desired Output
<?xml version="1.0" encoding="UTF-8"?>
<aa:Details xmlns:aa="urn:com.report">
<aa:Row>
<aa:Place>EEE</aa:Place>
<aa:PlaceID>E123</aa:PlaceID>
</aa:Row>
<aa:Row>
<aa:Place>FFF</aa:Place>
<aa:PlaceID>F123</aa:PlaceID>
</aa:Row>
</aa:Details>
I tried below XSLT code but it only removes the duplicates
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:aa="urn:com.report">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="aa:Row[aa:PlaceID = following::aa:Row/aa:PlaceID]"/>
</xsl:stylesheet>
Define a key
<xsl:key name="placeKey" match="aa:Row" use="aa:Place">
Make the second input document your primary input, and select document 1 as
<xsl:variable name="doc1" select="document('input1.xml')">
Then process document2 as
<xsl:template match="/">
<aa:Details xmlns:aa="urn:com.report">
<xsl:copy-of select="aa:Row[exists(key('placeKey', ., $doc1)]"/>
</aa:Details>
</xsl:template>
That's XSLT 2.0. If you're still using an XSLT 1.0 processor then as usual you'll have to jump through a few more hoops. It's a long time since I used XSLT 1.0 but I think you'll have to replace the copy-of with something like
<xsl:for-each select="aa:Row">
<xsl:variable name="row" select="."/>
<xsl:for-each select="$doc1">
<xsl:if test="key('placeKey', $row/Place)">
<xsl:copy-of select="$row"/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
If the input to the transformation is the combined set of data shown in your question, then the stated task is impossible because the processor has no way of knowing which nodes come from which set.
Related
I have a merged report data(data comes from two sources)as an input file and I needed to lookup a value based on a key. Currently my code is returning incorrectly looking up values. Since the size of the input data is expected to be large, I would like to use streaming for better performance.
Here is my input xml
Element Number'is the key to lookup. Xpath is 'Batch/Workers/Number`
Lookup Phone element based on Number' . Xpath isMergedOutput/Data/Row/Phone`
Sample Input
<?xml version="1.0" encoding="UTF-8"?>
<MergedOutput>
<Data>
<Row>
<Employee_Batch_Id>12567</Employee_Batch_Id>
<Phone>FirstEmp8013457896</Phone>
<Assignment_Id>5046150263</Assignment_Id>
</Row>
<Row>
<Employee_Batch_Id>12568</Employee_Batch_Id>
<Phone>SecondEmp7853457896</Phone>
<Assignment_Id>5046150263</Assignment_Id>
</Row>
</Data>
<Batch>
<Workers>
<Number>12567</Number>
<Contact>Work7864532890</Contact>
</Workers>
<Workers>
<Number>12568</Number>
<Contact>Work6782340167</Contact>
</Workers>
</Batch>
</MergedOutput>
Current XSLT3 code
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
exclude-result-prefixes="xs r1 r2 map"
version="3.0">
<xsl:output method="xml" indent="yes"/>
<xsl:mode streamable="yes" on-no-match="shallow-skip" use-accumulators="#all"/>
<xsl:accumulator name="FirstReportLookupValuePhone" as="xs:string" initial-value="''" streamable="yes">
<xsl:accumulator-rule match="Phone/text()" select="."/>
</xsl:accumulator>
<xsl:accumulator name="EmployeeIDLookup" as="map(xs:string,xs:string)" initial-value="map{}" streamable="yes">
<xsl:accumulator-rule match="Employee_Batch_Id/text()" select="map:put($value, string(.), accumulator-before('FirstReportLookupValuePhone'))"/>
</xsl:accumulator>
<xsl:template match="Batch">
<Workers>
<xsl:apply-templates select="Workers"/>
</Workers>
</xsl:template>
<xsl:template match="Workers">
<xsl:variable name="vWorkers" select="copy-of()"/>
<xsl:variable name="vMappedWorker" select="accumulator-after('EmployeeIDLookup')( normalize-space($vWorkers/Number))"/>
<Worker>
<WorkerID><xsl:value-of select="$vWorkers/Number"/></WorkerID>
<Work_Contact_Number><xsl:value-of select="$vWorkers/Contact"/></Work_Contact_Number>
<Home_Contact_Number><xsl:value-of select="$vMappedWorker"/></Home_Contact_Number>
</Worker>
</xsl:template>
</xsl:stylesheet>
Current output
<?xml version="1.0" encoding="UTF-8"?>
<Workers>
<Worker>
<WorkerID>12567</WorkerID>
<Work_Contact_Number>Work7864532890</Work_Contact_Number>
<Home_Contact_Number/> <!-- Value is empty, Expected value is FirstEmp8013457896 -->
</Worker>
<Worker>
<WorkerID>12568</WorkerID>
<Work_Contact_Number>Work6782340167</Work_Contact_Number>
<Home_Contact_Number>FirstEmp8013457896</Home_Contact_Number> <!-- Incorrect Value, Expected value is SecondEmp7853457896 -->
</Worker>
</Workers>
Expected Output
<?xml version="1.0" encoding="UTF-8"?>
<Workers>
<Worker>
<WorkerID>12567</WorkerID>
<Work_Contact_Number>Work7864532890</Work_Contact_Number>
<Home_Contact_Number>FirstEmp8013457896</Home_Contact_Number>
</Worker>
<Worker>
<WorkerID>12568</WorkerID>
<Work_Contact_Number>Work6782340167</Work_Contact_Number>
<Home_Contact_Number>SecondEmp7853457896</Home_Contact_Number>
</Worker>
</Workers>
Please could someone help me figure out how could i get the desired output?
The problem is that the accumulator matching Employee_Batch_ID tries to use the accumulator value for Phone; but because the Employee_Batch_ID appears before the Phone element, the Phone accumulator value isn't available yet.
I think you have to reverse the logic: when you encounter an Employee_Batch_ID/text(), save the ID value as a string in accumulator A; when you encounter a Phone/text(), add an ID=phone entry to a map held in Accumulator B.
I'm using a tool to import XML files into Dynamics NAV, but some parties providing the XML files skip empty nodes. My tool (external) can not handle those situation so I want to include XSLT to add the missing nodes. The xslt works fine for 1 node, but adding multiple nodes does not work. So I must be doing something wrong.
I'm building an integration to Dynamics NAV to insert Sales Orders. The orders are delivered from multiple parties using a XML file. However some of the parties providing the XML do not list all nodes in their XML file, they skip the empty ones. I'm using a tool build within Dynamics NAV (Add-on from other vendor) to import those files. However some XML files go wrong because of the fact that some (empty) nodes are missing in the XML file. I know this is an issue within the add-on but I need a solution on short notice. So created an XSLT to add the missing nodes. It works fine with 1 missing node, but it is not able to add both missing nodes. I'm not that familiar with XSLT so most of the times it is trial & error. Perhaps someone can help me with this.
This is the XML file format that is provided, The nodes that are sometimes missing is the DeliveryParty node and the DeliveryAddress part.
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<Orders>
<Order>
<Partner>
<SenderEANCode>9999999999999</SenderEANCode>
<RecipientEANCode>9999999999999</RecipientEANCode>
</Partner>
<OrderHeader>
<OrderVersion>008</OrderVersion>
<OrderTypeCode>220</OrderTypeCode>
<Document>
<DocumentNumber>34034040</DocumentNumber>
<Date>2019-04-18</Date>
</Document>
<DeliveryDate>2019-04-24</DeliveryDate>
<CompleteDelivery>YES</CompleteDelivery>
<Supplier>9999999999999</Supplier>
<Buyer>9999999999999</Buyer>
<Invoicee>9999999999999</Invoicee>
<DeliveryParty>9999999999999</DeliveryParty>
<DeliveryAddress>
<DeliveryName>Private Customer</DeliveryName>
<DeliveryStreet>Teststraat</DeliveryStreet>
<DeliveryCity>TestCity</DeliveryCity>
<DeliveryCountry>NL</DeliveryCountry>
<DeliveryTelNo></DeliveryTelNo>
<DeliveryEmail>test#test.com</DeliveryEmail>
</DeliveryAddress>
</OrderHeader>
<OrderLine>
<LineItemNumber>1</LineItemNumber>
<GTIN>9999999999999</GTIN>
<OrderedQuantity>
<Quantity>260</Quantity>
</OrderedQuantity>
</OrderLine>
</Order>
</Orders>
Sometimes the DeliveryParty node is missing and other times the DeliveryAddress part including subnodes is missing. I created the following XSLT to add those nodes but as it is trail and error I need some help to fix this. I'm a novice to XSLT, I can so some small changes but I do not use it frequently so knowledge is fading away quickly.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Orders/Order/OrderHeader[not(DeliveryParty)]">
<xsl:copy-of select="*"/>
<DeliveryParty/>
</xsl:template>
<xsl:template match="Orders/Order/OrderHeader[not(//DeliveryAddress)]">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<DeliveryAddress>
<DeliveryName></DeliveryName>
<DeliveryStreet></DeliveryStreet>
<DeliveryPostalCode></DeliveryPostalCode>
<DeliveryCity></DeliveryCity>
<DeliveryCountry></DeliveryCountry>
<DeliveryTelNo></DeliveryTelNo>
<DeliveryEmail></DeliveryEmail>
</DeliveryAddress>
</xsl:copy>
</xsl:template>
With above mentioned XSLT the DeliveryAddress node with it's subnodes is added but the deliveryparty is not.
When the file is delivered like this:
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<Orders>
<Order>
<Partner>
<SenderEANCode>9999999999999</SenderEANCode>
<RecipientEANCode>9999999999999</RecipientEANCode>
</Partner>
<OrderHeader>
<OrderVersion>008</OrderVersion>
<OrderTypeCode>220</OrderTypeCode>
<Document>
<DocumentNumber>34034040</DocumentNumber>
<Date>2019-04-18</Date>
</Document>
<DeliveryDate>2019-04-24</DeliveryDate>
<CompleteDelivery>YES</CompleteDelivery>
<Supplier>9999999999999</Supplier>
<Buyer>9999999999999</Buyer>
<Invoicee>9999999999999</Invoicee>
</OrderHeader>
<OrderLine>
<LineItemNumber>1</LineItemNumber>
<GTIN>9999999999999</GTIN>
<OrderedQuantity>
<Quantity>260</Quantity>
</OrderedQuantity>
</OrderLine>
</Order>
</Orders>
The outcome should be this:
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<Orders>
<Order>
<Partner>
<SenderEANCode>9999999999999</SenderEANCode>
<RecipientEANCode>9999999999999</RecipientEANCode>
</Partner>
<OrderHeader>
<OrderVersion>008</OrderVersion>
<OrderTypeCode>220</OrderTypeCode>
<Document>
<DocumentNumber>34034040</DocumentNumber>
<Date>2019-04-18</Date>
</Document>
<DeliveryDate>2019-04-24</DeliveryDate>
<CompleteDelivery>YES</CompleteDelivery>
<Supplier>9999999999999</Supplier>
<Buyer>9999999999999</Buyer>
<Invoicee>9999999999999</Invoicee>
<DeliveryParty></DeliveryParty>
<DeliveryAddress>
<DeliveryName></DeliveryName>
<DeliveryStreet></DeliveryStreet>
<DeliveryCity></DeliveryCity>
<DeliveryCountry></DeliveryCountry>
<DeliveryTelNo></DeliveryTelNo>
<DeliveryEmail></DeliveryEmail>
</DeliveryAddress>
</OrderHeader>
<OrderLine>
<LineItemNumber>1</LineItemNumber>
<GTIN>9999999999999</GTIN>
<OrderedQuantity>
<Quantity>260</Quantity>
</OrderedQuantity>
</OrderLine>
</Order>
</Orders>
How about:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="OrderHeader">
<xsl:copy>
<xsl:apply-templates/>
<xsl:if test="not(DeliveryParty)">
<DeliveryParty/>
</xsl:if>
<xsl:if test="not(DeliveryAddress)">
<DeliveryAddress>
<DeliveryName/>
<DeliveryStreet/>
<DeliveryPostalCode/>
<DeliveryCity/>
<DeliveryCountry/>
<DeliveryTelNo/>
<DeliveryEmail/>
</DeliveryAddress>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I have requirement where I have to add Namespace and xsi to the
element from the source xml with No Namespace.
In Source XML I am just getting the Nodes and there is No namespace
and another program needs BizTalk to add Namespace and XSI to the XML for its processing.
I tried:
Used add namespace pipeline component. (It just added
namespace and not the xsi bits)
Used Map for putting up the desired format and yes no luck as got
just the namespace.
Need your help around this.
My source XML is like
<?xml version="1.0" encoding="UTF-16"?>
<Document>
<CstmrPmtStsRpt>
<GrpHdr>
<MsgId></MsgId>
<CreDtTm></CreDtTm>
<InitgPty>
<Id>
<OrgId>
<BICOrBEI></BICOrBEI>
</OrgId>
</Id>
</InitgPty>
</GrpHdr>
<OrgnlGrpInfAndSts>
<OrgnlMsgId></OrgnlMsgId>
<OrgnlMsgNmId></OrgnlMsgNmId>
<OrgnlNbOfTxs></OrgnlNbOfTxs>
<OrgnlCtrlSum></OrgnlCtrlSum>
<GrpSts>ACCP</GrpSts>
</OrgnlGrpInfAndSts>
</CstmrPmtStsRpt>
</Document>
My Required format is as below:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="MyNamespace">
<CstmrPmtStsRpt>
<GrpHdr>
<MsgId></MsgId>
<CreDtTm></CreDtTm>
<InitgPty>
<Id>
<OrgId>
<BICOrBEI></BICOrBEI>
</OrgId>
</Id>
</InitgPty>
</GrpHdr>
<OrgnlGrpInfAndSts>
<OrgnlMsgId></OrgnlMsgId>
<OrgnlMsgNmId></OrgnlMsgNmId>
<OrgnlNbOfTxs></OrgnlNbOfTxs>
<OrgnlCtrlSum></OrgnlCtrlSum>
<GrpSts>ACCP</GrpSts>
</OrgnlGrpInfAndSts>
</CstmrPmtStsRpt>
</Document>
Use the namespace attribute of xsl:element like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*">
<xsl:element name="{local-name()}" namespace="MyNamespace">
<xsl:namespace name="xsi" select="'http://www.w3.org/2001/XMLSchema-instance'"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Edit: Since you need to work with XSLT-1.0. Use following stylesheet:
<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/Document">
<Document xmlns="MyNamespace"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:apply-templates/>
</Document>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}" namespace="MyNamespace">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Note, that you need to know your rootnode's name for this (in this case Document).
BizTalk Answer:
First, it's a good thing the incoming document has no namespace. Xml Namespaces are far, far, far more trouble than they're worth and should be avoided/removed whenever possible.
Second the output format is not valid Xml. "MyNamespace" is not a valid URI and can't be used for a Namespace. If this is what they are asking for, they need to fix that first.
But, if you must, your process should not be "add a namespace". What you're really doing is Transforming from SysA's Document to SysB's Document. For that, use a Map. You will use to practially identical Schemas, one with and one without the Target Namespace.
The Mapper will handle xsi for you as well, if it's needed.
Original source of xml
<SubdivisionType>
<ID>null</ID>
<Name>null</Name>
<Parent i:nil="true"/>
</SubdivisionType>
String 'null' is generated by E4X. I have to check if SubdivisionType/ID contains another value then 'null' then skip all SubdivisionType tag.
Here is how i do
<xsl:if test="SubdivisionType/ID[text()!=null]" >
...
</xsl:if>
I can't understand how xlst(saxon) treats string 'null'.
I don't know saxon specifically, but as far as I'm aware, that isn't a "null string"... it's a string with the value "null".
I would try changing...
text()!=null
to...
text()!='null'
so that it reads...
<xsl:if test="SubdivisionType/ID[text()!='null']">
#Simar,
if we conside below as the xml
<?xml version="1.0" encoding="utf-8"?>
<xml>
<SubdivisionType>
<ID>null</ID>
<Name>null</Name>
<Parent nil="true"/>
</SubdivisionType>
<SubdivisionType>
<ID>asd</ID>
<Name>null</Name>
<Parent nil="true"/>
</SubdivisionType>
</xml>
XSL:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" `xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match = "SubdivisionType[ID = 'null']" />
</xsl:stylesheet>
OUTPUT :
<?xml version="1.0" encoding="UTF-8"?>
<xml>
<SubdivisionType>
<ID>asd</ID>
<Name>null</Name>
<Parent nil="true"/>
</SubdivisionType>
</xml>
For unknown reason max function doesn't work.
XML input file:
test.xml
<?xml version="1.0" encoding="UTF-8"?>
<numbers>
<number>3</number>
<number>5</number>
<number>10</number>
<number>1</number>
</numbers>
XSL input file
test.xsl
<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/02/xpath-functions"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" >
<xsl:output method="xml" indent="yes" />
<xsl:template match="/numbers">
<numbers>
<xsl:value-of select="/numbers/number" />
fn:max(2, 3)
</numbers>
</xsl:template>
</xsl:stylesheet>
Output.xml
<?xml version="1.0" encoding="UTF-8"?>
<numbers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:fn="http://www.w3.org/2005/02/xpath-functions">3
fn:max(2, 3)
</numbers>
Input file is not important here, but I would like to have '3' instead of fn:max(2, 3). How to do it?
for this XSL file:
<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/02/xpath-functions"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" >
<xsl:output method="xml" indent="yes" />
<xsl:template match="/numbers">
<numbers>
<xsl:value-of select="/numbers/number" />
fn:max(2, 3)
<xsl:value-of select="max(/numbers/number)"/>
</numbers>
</xsl:template>
</xsl:stylesheet>
the following error occurs:
SystemId Unknown; Line #13; Column #49; Could not find function: max
SystemId Unknown; Line #13; Column #49; function token not found.
(Location of error unknown)java.lang.NullPointerException
(Location of error unknown)XSLT Error (javax.xml.transform.TransformerException)
: No xml-stylesheet PI found in: test.xml
Exception in thread "main" java.lang.RuntimeException: No xml-stylesheet PI foun
d in: test.xml
at org.apache.xalan.xslt.Process.doExit(Process.java:1155)
at org.apache.xalan.xslt.Process.main(Process.java:1128)
I used Xalan - Version Xalan Java 2.7.1, Command: java org.apache.xalan.xslt.Process -in test.xml -xsl test.xsl -out output.xml
There are several problems: max() needs to be in a value-of, and that you've said xsl:stylesheet version="2.0" for Xalan, which only supports XSLT 1.0. For 2.0, you'd need Saxon 9.x.
Since max() isn't part of XSLT 1.0, you need to invoke the EXSLT extension support, which Xalan does have:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:math="http://exslt.org/math">
<xsl:template match="/numbers">
<xsl:value-of select="math:max(number)"/>
</xsl:template>
</xsl:stylesheet>
or
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:math="http://exslt.org/math">
<xsl:template match="/">
<xsl:value-of select="math:max(numbers/number)"/>
</xsl:template>
</xsl:stylesheet>
You've put fn:max(2,3) in a text block. Nothing is going to interpret that. You need to put functions in value-of expressions if you want them to be evaluated.
Lavino,
Thanks for the response. I don't know why but I was pretty sure that Xalan supports 2.0... I've tested it and it works for Saxon 9.
You can use
<xsl:value-of select="max(number)" />
to get the max of all numbers.
Soln:
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/numbers">
<numbers>
<max>
<xsl:value-of select="max(number)"/>
</max>
<xsl:apply-templates/>
</numbers>
</xsl:template>
<xsl:template match="number">
<number>
<xsl:value-of select="."/>
</number>
</xsl:template>
</xsl:stylesheet>
You can omit the number template and <xsl:apply-templates/> if its not reqd. This will be the output with the above xslt:
<?xml version="1.0" encoding="UTF-8"?>
<numbers xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<max>10</max>
<number>3</number>
<number>5</number>
<number>10</number>
<number>1</number>
</numbers>