Want to get the preceding-sibling - xslt

I am parsing the XML like below,
<Service>
<ServiceName>
<Plans>
<Plan>
<PlanNumber>A</PlanNumber>
....
</Plan>
</Plans>
</Service>
<Service>
<ServieName>
<Plans>
<Plan>
<PlanNumber>B</PlanNumber>
....
</Plan>
</Plans>
</Service>
I am iterating through for-each Plans/Plan and trying to print preceding-sibling::Plan/PlanNumber, I am not getting anything.
I want this to iterate through the unique plan number so I am using an if statement next to the for-each. <xsl-if test="not(PlanNumber = preceding-sibling::Plan/PlanNumber)">
I am not getting through the PlanNumbers.

In your example, there is only one Plan in Plans (and only one Plans in Service). This means that Plan has no siblings and your attempt preceding-sibling::Plan/PlanNumber selects nothing.
To get the preceding PlanNumber from the context of Plan, you need to do:
../../preceding-sibling::Service/Plans/Plan/PlanNumber
or:
preceding::PlanNumber

<xsl:foreach select="Plan">
<xsl:foreach select="PlanNumber">
<xsl:if test="position()!=1">
<xsl:value-of select="preceding-sibling::text()"/>
</xsl:if>
</xsl:foreach>
</xsl:foreach>

Related

How to iterate a List and print it's content one by one in each groupFooter?

I just want to know, is there any way to iterate a List and print it's content one by one (incremental) in each groupFooter?
I create a group in my report, and in each groupFooter section, I want to display content from a java.util.List I sent from Java class via parameter.
Currently I just using jr:list and jr:listContents in my groupFooter, and the result is all contents from the list is printed in every groupFooter. I got an headache to solve this, so any help will relief me.
I don't think you should try to iterate the List to get content in a certain number of groupFooter, instead I would get content directly List based on index.
What we need is simple a pointer (position in list), in your case this number seems to be an incremented number every time we have a new group.
A variabile counting as group change is:
<variable name="countMyGroup" class="java.lang.Integer" incrementType="Group" incrementGroup="Group1" calculation="Count">
<variableExpression><![CDATA[""]]></variableExpression>
<initialValueExpression><![CDATA[0]]></initialValueExpression>
</variable>
With this simple variabile we will now have the current number of group that is displayed and we can add a textField with the value from or List using this number. see java.util.List.get(int index)
<parameter name="listOfStuff" class="java.util.List" isForPrompting="false"/>
.....
<textField>
<reportElement x="120" y="0" width="267" height="17" uuid="b45699d3-5d34-4d88-b7bc-2666cf787ace">
<printWhenExpression><![CDATA[$P{listOfStuff}.size()>=$V{countMyGroup}]]></printWhenExpression>
</reportElement>
<textFieldExpression><![CDATA[$P{listOfStuff}.get($V{countMyGroup}-1)]]></textFieldExpression>
</textField>
Note: the printWhenExpression will avoid IndexOutOfBoundsException, hence that the group number is higher then the size of our List
Full jrxml example, it use a dummy group changing on each record, to try it use a JREmptyDatasource with a couple of records.
<?xml version="1.0" encoding="UTF-8"?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="ListOnEachPage" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="33394f25-66fc-431b-ac82-88660e9115e5">
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="Empty 4 records"/>
<parameter name="listOfStuff" class="java.util.List" isForPrompting="false">
<defaultValueExpression><![CDATA[Arrays.asList(new String[]{"group 1","group 2","group 3"})]]></defaultValueExpression>
</parameter>
<queryString>
<![CDATA[]]>
</queryString>
<variable name="countMyGroup" class="java.lang.Integer" incrementType="Group" incrementGroup="Group1" calculation="Count">
<variableExpression><![CDATA[""]]></variableExpression>
<initialValueExpression><![CDATA[0]]></initialValueExpression>
</variable>
<group name="Group1">
<groupExpression><![CDATA[$V{REPORT_COUNT}]]></groupExpression>
<groupFooter>
<band height="34">
<textField>
<reportElement x="120" y="0" width="267" height="17" uuid="b45699d3-5d34-4d88-b7bc-2666cf787ace">
<printWhenExpression><![CDATA[$P{listOfStuff}.size()>=$V{countMyGroup}]]></printWhenExpression>
</reportElement>
<textFieldExpression><![CDATA[$P{listOfStuff}.get($V{countMyGroup}-1)]]></textFieldExpression>
</textField>
<textField>
<reportElement x="445" y="0" width="100" height="17" uuid="e5c46332-b137-4c55-99e4-265c87b8f97d"/>
<textFieldExpression><![CDATA[$V{countMyGroup}]]></textFieldExpression>
</textField>
</band>
</groupFooter>
</group>
<detail>
<band height="63" splitType="Stretch">
<staticText>
<reportElement x="140" y="20" width="264" height="30" uuid="1ec9f950-dd2d-4c18-a81a-b0da937eb1b5"/>
<textElement>
<font size="14"/>
</textElement>
<text><![CDATA[Just some text to simulate detail band]]></text>
</staticText>
</band>
</detail>
</jasperReport>
Output, see how values from list are extracted as long as we are within size of List
You need to make a variable which increment at your group level.
Step 2 its to use that variable in a simple textfield or what component you want (not a collection component) and put his expression like this : list.indexOf(countVariable)

Scope (root node, context) of XSLT "key" Element

I have an XSLT key defined. I need to access the key from within a for-each loop, where that loop is processing a node-set that is outside the scope of where the key was defined.
Snippet, where I've marked two lines, one which works and one which does not:
<xsl:value-of select="key('name', 'use')"/> <!-- works -->
<xsl:for-each select="$outOfScopeNodeSet">
<xsl:value-of select="key('name', 'use')"/> <!-- does not work -->
</xsl:for-each>
Is there a way to access the key from within the for-each loop?
XSLT 1.0, msxsl engine.
(I could not think of a reasonable way to provide a full working example for this. I'm also not sure of the correct terminology, such as "scope" - perhaps if I knew the correct terminology I'd be able to find my answer already. If the question is not clear enough please let me know and I'll try to edit it into better shape.)
In XSLT 1.0, keys do not work across documents. It seems that your $outOfScopeNodeSet contains a node-set whose root node is different from the root node of the XML document being processed (probably created by the exsl:node-set() function?) - while the key is supposed to fetch a value from the processed XML document.
To resolve this problem, you need to return the context back to the processed XML document before calling the key() function, for example:
<xsl:variable name="root" select="/" />
<xsl:for-each select="$outOfScopeNodeSet">
<xsl:variable name="use" select="some-value" />
<xsl:for-each select="$root">
<xsl:value-of select="key('name', $use)"/>
</xsl:for-each>
</xsl:for-each>

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,':')

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>

How to manipulate xml data in Oracle SOA suite?

<Employees manager="101" xmlns:ns1="http://www.example.org" xmlns="http://www.example.org">
<ns1:person ssn="101">
<ns1:firstName>Lakshminarayana</ns1:firstName>
<ns1:lastName>medikoda</ns1:lastName>
</ns1:person>
<ns1:person ssn="102">
<ns1:firstName>narasimha</ns1:firstName>
<ns1:lastName>mannepalli</ns1:lastName>
</ns1:person>
<ns1:person ssn="103">
<ns1:firstName>venu</ns1:firstName>
<ns1:lastName>ponakala</ns1:lastName>
</ns1:person>
</Employees>
I want to append new records and remove some records from this file in oracle soa
You should not be using XSLT to make this adjustment, you should be using the BPELX functions in an Assign activity.
To append a new record into the list you should be doing the following
bpelx:append
The bpelx:append extension in an assign activity enables a BPEL process to append the contents of one variable, expression, or XML fragment to another variable's contents.
<bpel:assign>
<bpelx:append>
<bpelx:from ... />
<bpelx:to ... />
</bpelx:append>
</bpel:assign>
The following example will show you how to implement this in your example.
<bpel:assign>
<bpelx:append>
<from variable="variableFrom"
query="variableFromQuery" />
<to variable="variableTo"
query="/ns1:Employees/ns1:person" />
</bpelx:append>
</bpel:assign>
To remove this from the queue you should
The bpelx:remove extension in an assign activity enables a BPEL process to remove a variable.
<bpel:assign>
<bpelx:remove>
<bpelx:target variable="variableName" part="Employee" query="query to match node you want to remove" />
</bpelx:remove>
</bpel:assign>