Is there any way to get how many time WSO2 ESB iterator mediator iterated, in terms of some counter value ?
There is as many iteration as xml fragments given by the xpath expression you've defined inside iterate mediator and you can use xpath function "count" to find this value, exemple :
message :
<root>
<value>
...
</value>
<value>
...
</value>
</root>
Mediation :
<iterate expression="//value">
<target>
...
</target>
</iterate>
XPATH giving the number of iteration : count(//value)
Internally, a property "messageSequence" or "messageSequence.ID" (where ID is the value of the iterate mediator's optional id attribute) is initialized with such a counter (it give you something like 0/2 and 1/2 with my sample) but I'm not sure you should use that...
Related
I've got a list, with paired values:
aircon, aircon_no - these two values are a pair
ABS, ABS_no
heatedseats, heatedseats_no
etc.
So a pair is two values that start with the same substring. These values are stored in the #type attribute.
I've got about 50 pairs in my data.
I want to process an XML which looks like this:
<object type="aircon" id="1">
..
</object>
<object type="ABS" id="2">
..
</object>
<object type="heatedseats" id="3">
..
</object>
<object type="ABS" id="4">
..
</object>
<object type="ABS_no" id="5">
..
</object>
This is a short excerpt, the data contains hundreds of "object" nodes.
The operation depends on the type attribute of the "object" node, and the type attr. of the preceding "object" node. I could find those like this:
<if test="#type='ABS_no' and preceding-sibling::object/#type='ABS'"> ...
My list of paired values is quite long, so I get a long list of these if statements.
Is there a way to avoid creating a long list of if statements, and instead have a more general statement that works for each of my pairs:
<if test="#type='-second value of a pair-' and preceding-sibling::object[1]/#type='-first value of that same pair-'">
and get the whole list of pairs into a single statement?
The goal is to find node ABS_no if it is preceded by node ABS (so #id='5' in my example list), and do this for each pair of values.
The XSLT is passthrough, except for one template that matches the nodes. If these pass the test, an extra subnode is added to the node.
I use XSLT2, but XSLT3 is an option if it helps.
a pair is two values that start with the same letter.
...
The goal is to find node B2 if it is preceded by node B1
I am not sure that constitutes a well-defined problem (what if there is a sequence B1, B2, B3?), but I believe this will do what you asked for:
<xsl:for-each select="object[position() > 1 and starts-with(#type, substring(preceding-sibling::object[1]/#type, 1, 1))]">
<!-- do something -->
</xsl:for-each>
--- added in responses to your edit ---
the _ is the separator between the common substring of a pair and the unique part of the values
In such case you could select (or match):
object[substring-before(#type, '_') = preceding-sibling::object[1]/#type]
But if you can use XSLT 2.0, grouping might be a better alternative.
You could use <xsl:for-each-group select="object" group-by="replace(#type, '_.*$', '')" and then each pair would be a group.
Is there a regex to check for empty elements for the XML below? So I want to check whether or not everything below the <ClientRequest> tags are populated or not?
<Response xmlns="http://Test/Types">
<ClientRequest>
<Name>TEST</Name>
<Id><222/Id>
<Parameters>
<SID>123456</SID>
</RequestParams>
<StartDate>2017-10-13T23:00:01.000+01:00</StartDate>
<EndDate>2017-10-14T22:59:59.000+01:00</EndDate>
<URL></URL>
</ClientRequest>
<Install/>
<Types/>
<LR/>
<Package/>
<Services/>
<Issues/>
<Complaints/>
</Response>
Use an XML parser or XPath, not regex, to check or parse XML.
This XPath,
//*[not(text()) and not(*)]
will select all elements that have no text or element children.
This XPath,
//*[not(node())]
will select all empty elements (also disallowing comment and PI children).
Note that your XML is not well-formed. Here it is with corrections:
<Response xmlns="http://Test/Types">
<ClientRequest>
<Name>TEST</Name>
<Id>222</Id>
<Parameters>
<SID>123456</SID>
</Parameters>
<StartDate>2017-10-13T23:00:01.000+01:00</StartDate>
<EndDate>2017-10-14T22:59:59.000+01:00</EndDate>
<URL></URL>
</ClientRequest>
<Install/>
<Types/>
<LR/>
<Package/>
<Services/>
<Issues/>
<Complaints/>
</Response>
Note also that you could wrap either of the above XPaths in boolean() or count() to return an indicator or count of the presence of such populated elements.
I have the following XML structure:
<itemsWithLabels>
<itemLabelValue>
<label>A</label>
<value>a</value>
</itemLabelValue>
<itemLabelValue>
<label>B</label>
<value>b</value>
</itemLabelValue>
<itemLabelValue>
<label>C</label>
<value>c</value>
</itemLabelValue>
</itemsWithLabels>
Using XSL I want to be able to get the value from <value> by knowing the label in <label>.
So my transformation looks like this:
<xsl:value-of select="$content/itemsWithLabels/itemLabelValue/value[#label='A']" />
But clearly something is wrong because I don't have any output.
What am I doing wrong?
Try:
<xsl:value-of select="$content/itemsWithLabels/itemLabelValue[label='A']/value" />
$content/itemsWithLabels/itemLabelValue[label='A'] gets itemLabelValue elements with a label element child having value A. The /value part gets the child value element.
I'm developing a BPEL service using JDeveloper 11.1.1.5.0.
The API's response contains some recurring fields and I'm trying to use a for-each loop to map them with the final web-service's response parameters.
The API's response structure is like this :
<Data>
<Item>
<F6181_SubsWalletCounter>-1</F6181_SubsWalletCounter>
<FBalanceExpDate>2013-08-13T00:00:00</FBalanceExpDate>
<FResetWalletCounterValue>0</FResetWalletCounterValue>
<FRecurringPeriod>0</FRecurringPeriod>
<FRecurringRefreshDate>1899-12-30T00:00:00</FRecurringRefreshDate>
<FRecurringRefreshDay>0</FRecurringRefreshDay>
<F6150_AccountProfileId>18</F6150_AccountProfileId>
<FLimit>0</FLimit>
<F8345_PaymentDebt>0</F8345_PaymentDebt>
<F9217_MinBalance>0</F9217_MinBalance>
<F9218_MaxPaymentDebt>-1</F9218_MaxPaymentDebt>
</Item>
<Item>
<F6181_SubsWalletCounter>-1</F6181_SubsWalletCounter>
<FBalanceExpDate>2013-08-13T00:00:00</FBalanceExpDate>
<FResetWalletCounterValue>0</FResetWalletCounterValue>
<FRecurringPeriod>0</FRecurringPeriod>
<FRecurringRefreshDate>1899-12-30T00:00:00</FRecurringRefreshDate>
<FRecurringRefreshDay>0</FRecurringRefreshDay>
<F6150_AccountProfileId>18</F6150_AccountProfileId>
<FLimit>0</FLimit>
<F8345_PaymentDebt>0</F8345_PaymentDebt>
<F9217_MinBalance>0</F9217_MinBalance>
<F9218_MaxPaymentDebt>-1</F9218_MaxPaymentDebt>
</Item>
</Data>
The <Item> element and its sub-elements could repeat multiple times maintaining the exact structure within itself. Out of these sub elements, few are to be mapped with the final response parameters.
The xsl code is :
<ns2:responseBody>
<ns2:balanceInfo>
<ns2:balance>
<xsl:for-each select=
"/tns:Subscriber_WalletInfo_GetResponse/Data/Item">
<ns2:wallet>
<xsl:value-of select="F6091_WalletTypeName"/>
</ns2:wallet>
</xsl:for-each>
<ns2:expirationDate>
<xsl:value-of select="FBalanceExpDate"/>
</ns2:expirationDate>
<ns2:balanceAmount>
<xsl:value-of select="F9261_Balance"/>
</ns2:balanceAmount>
<ns2:unit>
<xsl:value-of select="F8341_CurrencyName"/>
</ns2:unit>
</ns2:balance>
</ns2:balanceInfo>
<ns3:Error>
<ns3:description>
<xsl:value-of select="/tns:Subscriber_WalletInfo_GetResponse/ErrorDescription"/>
</ns3:description>
</ns3:Error>
</ns2:responseBody>
But the response doesn't get mapped with this xsl. I'm not sure if I've made any syntactical error or if any namespace is missing.
Any kind of guidance would be great!
I'm not sure if I've made any syntactical error or if any namespace is missing.
Right both times, I think.
First, the syntax errors.
If the XML introduced with the words "The xsl code is" is in fact the entire stylesheet, then your first syntactic error is that your stylesheet is not namespace-well-formed: you have not declared any of the namespace prefixs ns2, ns3, xsl.
Your second syntactic error is at the XSLT level: the namespace prefix tns is also not declared.
Your third syntactic error is that the outermost element does not include any xsl:version attribute.
When I supply dummy namespace declarations for the unbound prefixes (and http://www.w3.org/1999/XSL/Transform for the prefix xsl) and supply an xsl:version="1.0" attribute on the outermost element, then the stylesheet becomes a legal XSLT 1.0 stylesheet, using the "literal result element as stylesheet" option.
So much for the syntax errors. When I run the repaired stylesheet on the input you supply, I get output. Not the output you want, but it's progress:
<?xml version="1.0"?>
<ns2:responseBody xmlns:ns2="http://example.com/ns2"
xmlns:ns3="http://example.com/ns3"
xmlns:tns="http://example.com/tns">
<ns2:balanceInfo>
<ns2:balance>
<ns2:expirationDate/>
<ns2:balanceAmount/>
<ns2:unit/>
</ns2:balance>
</ns2:balanceInfo>
<ns3:Error>
<ns3:description/>
</ns3:Error>
</ns2:responseBody>
Now the semantic errors, which include but are not limited to a namespace error.
You're not getting any information about your input here, because the select expressions in your stylesheet (specifically /tns:Subscriber_WalletInfo_GetResponse/Data/Item and /tns:Subscriber_WalletInfo_GetResponse/ErrorDescription) aren't matching anything. Both of these path expressions say, roughly:
Start at the root of the document (that's the /).
The outermost element will be named Subscriber_WalletInfo_GetResponse, in the namespace bound to prefix tns.
Within that element, the second select expression searches for a child named ErrorDescription which is not namespace-qualified. The first expression searches for a child (or: the set of all children) named Data, and then within the Data element(s), the set of all children named Item, and evaluates the contents of the for-each instruction once for each of them. The elements Item and Data are both expected to be namespace-unqualified.
In the data you show, by contrast, the outermost element is not named Subscriber_WalletInfo_GetResponse and is not namespace-qualified. Naturally, neither select expression doesn't match anything: they both fail at step 2.
I am fairly new to XML dev.. I had a few questions regarding XML parsing with XPATH and libxml.
I have an XML structured as :
<resultset>
<result count=1>
<row>
<name> He-Man! </name>
<home> Greyskull </home>
<row>
</result>
<result count=2>
<row>
<name> Spider-Man</name>
<home> Some downtown apartment </home>
<row>
<row>
<name> Disco-Man!</name>
<home> The 70's dance floor </home>
<row>
</result>
<resultset>
I need to pick out the names from this XML , but where the count is 2 , i need it only from the first record. I ran through a few tutorials, but i am unable to come up with an XPATH query which would serve this purpose.
/name will select all name elements.
/result[#count > 1 ]/row[1]/name | /result[#count =1 ]/row/name
Is this possible to be done with XPATH ? Is this better to be done via XPATH or by walking the XML tree?
Can some one point me to some complex searches through out XML's ?
Edit : The actual scenario requires select a subset of the XML row , which are nested at 2 levels at times. This sounds like i need to OR '|' many paths to select the nodes i require... I am not sure if that would be efficient as opposed to walking a tree... The above is typed to replicate the problem :)
Thanks!
Try this XPath -
/resultset/result[#count=2]/row/name
This will give a list of all nodes falling under this XPath. From this just take the first element (as you needed only the first record).
I'd probably keep my xpath simpler and just extract both cases, then loop over both node sets.
If you do need to go down the single xpath route, you should try out your xpath expressions in something that lets you enter them live, rather than having to recompile C/C++ code. You should be able to do that by loading your XML into firefox and using firebug - for example typing $x('//name') in the firebug console gives three nodes.
NOTE however that your XML is invalid... You have a bunch of "<row>"s that should be "</row>" and the same for "<resultset>" and your counts need to be
<result count="1">
i.e. with quote marks around the value.