I'm trying to get the value of SERepeatKey if ItemOID REQUIRED.REQ_V has a value of "1".
In the below case I want to return the value 2.
Is this possible with this XML? If so how?
With this I was able to do it if there was only 1 "Data" node but now with 2 I am at a loss. In XPath tester I get the below error message.
string(ODM/Data/SData[#SKey='003-003' and SiteRef[#LOID='SE 003']]/SEData[#SEOID='UNSCHEDULED']/#SERepeatKey)
"Unable to perform XPath operation. A sequence of more than one item is not allowed as the first argument of string() (#SERepeatKey, #SERepeatKey)"
<ODM>
<Data SOID="(DEV)" MetaDataVersionOID="" >
<SData SKey="003-003" >
<SiteRef LOID="SE 003"/>
<SEData SEOID="UNSCHEDULED" SERepeatKey="1">
<FData FOID="REQUIRED" FormRepeatKey="1">
<IGData IGOID="REQUIRED" IGRepeatKey="0" TransactionType="Upsert">
<IData ItemOID="REQUIRED.REQ_V" Value="0" />
</IGData>
</FData>
</SEData>
</SData>
</Data>
<Data SOID="(DEV)" MetaDataVersionOID="" >
<SData SKey="003-003" >
<SiteRef LOID="SE 003"/>
<SEData SEOID="UNSCHEDULED" SERepeatKey="2">
<FData FOID="REQUIRED" FormRepeatKey="1">
<IGData IGOID="REQUIRED" IGRepeatKey="0" TransactionType="Upsert">
<IData ItemOID="REQUIRED.REQ_V" Value="1" />
</IGData>
</FData>
</SEData>
</SData>
</Data>
<Data SOID="(DEV)" MetaDataVersionOID="" >
<SData SKey="003-003" >
<SiteRef LOID="SE 003"/>
<SEData SEOID="UNSCHEDULED" SERepeatKey="3">
<FData FOID="REQUIRED" FormRepeatKey="1">
<IGData IGOID="REQUIRED" IGRepeatKey="0" TransactionType="Upsert">
<IData ItemOID="REQUIRED.REQ_V" Value="1" />
</IGData>
</FData>
</SEData>
</SData>
This XPath should do what you are looking for:
//Data[.//IData[#ItemOID='REQUIRED.REQ_V' and #Value='1']]//SEData/#SERepeatKey
According to the presented XML looks like you can even omit #ItemOID='REQUIRED.REQ_V' and make this expression simpler
//Data[.//IData[#Value='1']]//SEData/#SERepeatKey
Related
The #Value='1' Does not seem to be evaluating in this expression below as it returns both nodes of SEventData instead of only one that has a #Value of '1'. What am I missing?
Source:
<CData>
<SData SKey="006" >
<SEventData SEventOID="UNS" SEventRepeatKey="2">
<FData FOID="REQUIRED" FRepeatKey="1">
<ItemGroupData ItemGroupOID="REQUIRED" ItemGroupRepeatKey="0"
TransactionType="Upsert">
<ItemData ItemOID="REQ" Value="0" />
</ItemGroupData>
</FData>
</SEventData>
<SEventData SEventOID="UNS" SEventRepeatKey="3">
<FData FOID="REQUIRED" FRepeatKey="1">
<ItemGroupData ItemGroupOID="REQUIRED" ItemGroupRepeatKey="0"
TransactionType="Upsert">
<ItemData ItemOID="REQ" Value="1" />
</ItemGroupData>
</FData>
</SEventData>
</SData>
</CData>
with expression
//CData[.//SData[#SKey='006']/SEventData/FData/ItemGroupData/ItemData[#ItemOID='REQ' and #Value='1']]//SEventData
returns both instead of one
Element='<SEventData SEventOID="UNS" SEventRepeatKey="2">
<FData FOID="REQUIRED" FRepeatKey="1">
<ItemGroupData ItemGroupOID="REQUIRED"
ItemGroupRepeatKey="0"
TransactionType="Upsert">
<ItemData ItemOID="REQ" Value="0"/>
</ItemGroupData>
</FData>
</SEventData>'
Element='<SEventData SEventOID="UNS" SEventRepeatKey="3">
<FData FOID="REQUIRED" FRepeatKey="1">
<ItemGroupData ItemGroupOID="REQUIRED"
ItemGroupRepeatKey="0"
TransactionType="Upsert">
<ItemData ItemOID="REQ" Value="1"/>
</ItemGroupData>
</FData>
</SEventData>'
You can use this XPath in order to locate what you are looking for:
//SEventData[.//FData/ItemGroupData/ItemData[#ItemOID='REQ' and #Value='1']]
Your current XPath expression returns the root node //CData containing in it the following condition: .//SData[#SKey='006']/SEventData/FData/ItemGroupData/ItemData[#ItemOID='REQ' and #Value='1'].
So yes, //CData has inside it the condition as above and when you trying to locate //SEventData inside that //CData it returns you both //SEventData nodes.
What you should do here is to locate //SEventData node itself based on your condition as I wrote at the beginning:
//SEventData[.//FData/ItemGroupData/ItemData[#ItemOID='REQ' and #Value='1']]
I have an XPath expression that returns the following items but need to get the values from them. (respectively "2" & "3" but entire attribute would work too)
(my xml and path expression is here: Getting Upper XPath Value Based on Lower XML value)
Attribute='SERepeatKey =2'
Attribute='SERepeatKey =3'
This doesn't work
NodeList nl = (NodeList) xPath.compile(strXPath).evaluate(docODM, XPathConstants.NODESET);
for (int x = 0; x < nl.getLength(); x++){
Node ser = nl.item(x);
String sSer = ser.getAttributes().getNamedItem("SERepeatKey").getNodeValue().toString();
}
I removed the #SERepeatKey from the previous XPath statement to return the entire xml nodes then the above statement worked returning the "2" and "3" values.
<Data SOID="(DEV)" MetaDataVersionOID="" >
<SData SKey="003-003" >
<SiteRef LOID="SE 003"/>
<SEData SEOID="UNSCHEDULED" SERepeatKey="2">
<FData FOID="REQUIRED" FormRepeatKey="1">
<IGData IGOID="REQUIRED" IGRepeatKey="0" TransactionType="Upsert">
<IData ItemOID="REQUIRED.REQ_V" Value="1" />
</IGData>
</FData>
</SEData>
</SData>
</Data>
<Data SOID="(DEV)" MetaDataVersionOID="" >
<SData SKey="003-003" >
<SiteRef LOID="SE 003"/>
<SEData SEOID="UNSCHEDULED" SERepeatKey="3">
<FData FOID="REQUIRED" FormRepeatKey="1">
<IGData IGOID="REQUIRED" IGRepeatKey="0" TransactionType="Upsert">
<IData ItemOID="REQUIRED.REQ_V" Value="1" />
</IGData>
</FData>
</SEData>
</SData>
<foo>
<bar id="1" score="100" group="beginner" />
<bar id="2" score="200" group="beginner" />
<bar id="3" score="300" group="expert" />
...
</foo>
I try use like this, but something wrong (xpath 1.0)
foo/bar[#group='beginner' and not(#score<= preceding-sibling::bar/#score) and not(#score<=following-sibling::bar/#score)]
using xpath 1.0
/foo/bar[#group='beginner'][(not(preceding-sibling::bar[#group='beginner']/#score >= #score) and not(following-sibling::bar[#group='beginner']/#score > #score)) or (not(preceding-sibling::bar[#group='beginner']/#score <= #score) and not(following-sibling::bar[#group='beginner']/#score < #score))]/#score
We are attempting to expose a new field to only two groups (of many) within a TFS team project. We would like to implement a rule to the WIT object for which multiple values would satisfy the issue.
We have tried nested..
<WHENNOT field="System.AreaId" value="1"/>
<WHENNOT field="System.AreaId" value="2"/>
repeated...
<WHENNOT field="System.AreaId" value="1">
</WHENNOT>
<WHENNOT field="System.AreaId" value="2">
</WHENNOT>
and some guesses to the syntax..
<WHENNOT field="System.AreaId" value="1 or 2"/>
<WHENNOT field="System.AreaId" value="1 || 2"/>
<WHENNOT field="System.AreaId" value="1, 2"/>
without achieving the intended result.
<FIELD name="Original Estimate" refname="Microsoft.VSTS.Scheduling.OriginalEstimate" type="Double" reportable="measure" formula="sum">
<HELPTEXT>Initial value for Remaining Work - set once, when work begins</HELPTEXT>
<WHENNOT field="System.AreaId" value="24">
<READONLY />
</WHENNOT>
<WHENNOT field="System.State" value="To Do">
<READONLY />
</WHENNOT>
<WHEN field="System.State" value="Done">
<REQUIRED />
</WHEN>
</FIELD>
We would like to show the field based on whether the WIT is associated with Area ID 1 or 2, but otherwise hide from all of others.
You can't combine 2 WHENNOT because they cancel each other.
You need to use <WHEN field="System.AreaId" value="{id}"> <READONLY> </WHEN>
with all the areas (unless 1 and 2).
I try to write custom rule in sonar (plsql) by copy xpath rule. The task of this rule is to mark 'rollback to savepoint' statement where savepoint statement is missing.
For 2 savepoint and 3 rollback statements the AST (Abstract Syntax Tree) looks like:
<PROCEDURE_DEFINITION>
...
<SAVEPOINT>
<IDENTIFIER tokenValue="SAVEPOINT" />
<IDENTIFIER tokenValue="spA" />
<SEMICOLON tokenValue=";" />
</SAVEPOINT>
...
<SAVEPOINT>
<IDENTIFIER tokenValue="SAVEPOINT" />
<IDENTIFIER tokenValue="spB" />
<SEMICOLON tokenValue=";" />
</SAVEPOINT>
...
<ROLLBACK>
<IDENTIFIER tokenValue="ROLLBACK" />
<TO />
<IDENTIFIER tokenValue="SAVEPOINT" />
<IDENTIFIER tokenValue="spB" />
<SEMICOLON tokenValue=";" />
</ROLLBACK>
...
<ROLLBACK>
<IDENTIFIER tokenValue="ROLLBACK" />
<TO />
<IDENTIFIER tokenValue="SAVEPOINT" />
<IDENTIFIER tokenValue="spA" />
<SEMICOLON tokenValue=";" />
</ROLLBACK>
...
<ROLLBACK>
<IDENTIFIER tokenValue="ROLLBACK" />
<TO />
<IDENTIFIER tokenValue="SAVEPOINT" />
<IDENTIFIER tokenValue="spX" />
<SEMICOLON tokenValue=";" />
</ROLLBACK>
...
</PROCEDURE_DEFINITION>
I search for XPath query that marks last rollback because savepoint spX is missing.
But this xpath marks last both rollbacks
//PROCEDURE_DEFINITION//ROLLBACK[
IDENTIFIER[
#tokenValue =
./ancestor::PROCEDURE_DEFINITION
//SAVEPOINT/IDENTIFIER[2]/#tokenValue
]
]
Any suggestions?
EDIT:
I found this suboptimal solution:
//PROCEDURE_DEFINITION//ROLLBACK
[
not(
./IDENTIFIER[3]/#tokenValue =
ancestor::PROCEDURE_DEFINITION//SAVEPOINT/IDENTIFIER[2]/#tokenValue
)
]
PLSQL is case insensitive. But when i add translate function, i get marked first and last ROLLBACK node. I think all rollback's names will agreed with first savepoint's name?
First of all, according to the AST you show, it seems to me that this is the PL/SQL code you want to run your XPath query on:
DECLARE
PROCEDURE foo AS
BEGIN
SAVEPOINT spA;
SAVEPOINT spB;
ROLLBACK spB; -- Compliant
ROLLBACK spA; -- Compliant
ROLLBACK spX; -- Non-Compliant
END;
BEGIN
NULL;
END;
/
When I run your first XPath query using the SSLR PL/SQL Toolkit, the rollbacks to 'spB' and 'spA' are selected, but not the one to 'spX'.
Your second XPath query selects all of them.
It seems to me that you only want to select the one to 'spX', as there is no corresponding savepoint.
A trivial change to your first query allows to reverse the selected nodes, by negating the condition using not():
//PROCEDURE_DEFINITION//ROLLBACK[
not(IDENTIFIER[
#tokenValue =
./ancestor::PROCEDURE_DEFINITION
//SAVEPOINT/IDENTIFIER[2]/#tokenValue
])
]
But I would actually recommend that you drop the PROCEDURE_DEFINITION part of the query, as SAVEPOINT and ROLLBACK statements are also valid within functions or anonymous blocks:
//ROLLBACK[not(IDENTIFIER[#tokenValue = //SAVEPOINT/IDENTIFIER[2]/#tokenValue])]