Xpath - how to get parent based on its child's attribute - xpath

I have XML like below
<root>
<Success />
<Warnings>
</Warnings>
<Results>
<Result SequenceNumber="1">
<ResultchildOne>
<ResultChildOTwo>
<ElementA>
<ElementB ImportantAttribute="xxx" >
</ElementB>
</ElementA>
<ElementA>
<ElementB ImportantAttribute="yyy">
</ElementB>
</ElementA>
</ResultChildOTwo>
</ResultchildOne>
</Result>
<Result SequenceNumber="1">
<ResultchildOne>
<ResultChildOTwo>
<ElementA>
<ElementB ImportantAttribute="another value">
</ElementB>
</ElementA>
<ElementA>
<ElementB ImportantAttribute="xxx" >
</ElementB>
</ElementA>
</ResultChildOTwo>
</ResultchildOne>
</Result>
</Results>
I try to write xPath to select all Result elements which first child node ElementB has attribute ImportantAttribute="xxx" and its second child node ElementB has attribute ImportantAttribute="yyy". Can anyone help?

This works for the sample document:
//Result[ResultchildOne/ResultChildOTwo[ElementA[1]/ElementB[#ImportantAttribute='xxx']]
[ElementA[2]/ElementB[#ImportantAttribute='yyy']]]

Related

Struts 2 validation not working

I am trying to use struts 2 custom validation framework for validations, however that does not seem to be working. I am working on a very big project and the module I'm working on, I'm trying to implement this.
The problem struts 2 is not detecting my validation.xml. I tried creating a sample project and and used this validation.xml and it is working, but the same is not working in the project.
I am using model driven , I hope that should not be the problem.
The basic validations provided by action support are working fine but not my validations.
<interceptors>
<interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />
<interceptor name="browserCachingInterceptor" class="com.comviva.im.ui.interceptor.BrowserCachingInterceptor" />
<interceptor name="sessionHijackInterceptor" class="com.comviva.im.ui.interceptor.SessionHijackInterceptor" />
<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor" />
<interceptor-stack name="defaultSecurityStack">
<interceptor-ref name="defaultStack">
<param name="exception.logEnabled">true</param>
<param name="exception.logLevel">DEBUG</param>
</interceptor-ref>
<interceptor-ref name="tokenSession">
<param name="excludeMethods">*</param>
</interceptor-ref>
<interceptor-ref name="sessionHijackInterceptor" />
<interceptor-ref name="browserCachingInterceptor" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="defaultSecurityStack"></default-interceptor-ref>
The interceptor declaration is also fine.
I tried for days but still cant figure out the problem. the only option remaining is debug.
Can anybody suggest me where should I be looking for. Where is the validation.xml file is loaded in ActionInvocation so that I can check if validation file was loaded properly or not.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<field name="nodeId">
<field-validator type="required">
<message key="errors.required"/>
</field-validator>
<field-validator type="int">
<param name="min">1</param>
<param name="max">10000</param>
<message>bar must be between ${min} and ${max}, current value is ${bar}.</message>
</field-validator>
</field>
<field name="selfISDNNumber">
<field-validator type="required">
<message key="errors.required"/>
</field-validator>
</field>
</validators>
This is extract from my action class:
public class NodeAction extends BaseAction implements ModelDriven<NodeConfigurationForm>, ParameterAware ,Preparable {
NodeConfigurationForm nodeConfigForm = new NodeConfigurationForm();
private static final Logger logger = Logger.getLogger(NodeAction.class);
private NodeConfigurationService configurationService;
private List<NodeConfiguration> nodeListTable = null;
Map<String , String[]> requestParams;
private int isFallBackChannelEnable;
private int smsSupportEnable;
private ServletContext servletContext;
MY NodeAction class extends BaseAction which extends ActionSupport which by default is validation aware.So NodeAction should work with custom validations also.
This is extract from my struts.xml regarding actions:
<action name="createGWNode" method="create" class="com.comviva.im.ui.ussdGateway.action.NodeAction">
<result name="success" type="tiles">createGWNode</result>
</action>
<action name="addGWNode" method="add" class="com.comviva.im.ui.ussdGateway.action.NodeAction">
<result name="success" type="chain">listGWNodes</result>
<result name="input" type="tiles">createGWNode</result>
<result name="error" type="tiles">createGWNode</result>
</action>
<action name="editGWNode" method="edit" class="com.comviva.im.ui.ussdGateway.action.NodeAction">
<result name="success" type="tiles">createGWNode</result>
</action>
<action name="updateGWNode" method="update" class="com.comviva.im.ui.ussdGateway.action.NodeAction">
<result name="success" type="redirect">listGWNodes</result>
<result name="input" type="tiles">createGWNode</result>
<result name="error" type="tiles">createGWNode</result>
</action>
And this is my jsp
<s:textfield name="nodeId" required="true" theme="simple" />reado
<s:radio name="status" list="#{'1':'Enable','0':'Disable'}" theme="simple"></s:radio>
<s:textfield name="gwInstanceName" theme="simple" />
<s:textarea name="description" cols="30" rows="2" theme="simple"/>
<s:textfield name="serverIp" theme="simple"/>
<s:textfield name="serverIp" theme="simple" readonly=< s:textfield name="loginUserId" theme="simple"/>
<s:password name="loginPassword" showPassword="true" theme="simple"/>
<s:textfield name=" selfISDNNumber " theme="simple "/>
<s:select name="logLevel " list="logLevelList " theme="simple "/>
Note: Please remove _ Underscore from selfISDN_num
Check proper jar files.
Xwork: Core 2.3.16.2 API
And check getter , setters
Note: Please check package name in struts.xml, does it extend struts-default?
<package name="Registration" namespace="/" extends="struts-default">
...
</package>
Finally found what was going wrong.
The DTD specified in validaiton.xml was wrong. The specifed DTD is for 2.3 onwards. I was using struts with a lower version.
I am now using
<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator 1.0//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">

xpath usage in logi info

I have to massage some XML like this:
<Action ID="actDashboardRenamePanel" Type="Link">
<Target Type="Link" Link="javascript: LogiXML.Dashboard.pageDashboard.rdShowRenamePanel('rdDashboardPanelID', 'rdPnlInstanceID');" ID="tgtRenamepanel" />
</Action>
</PopupOption>
<PopupOption Caption="Remove" ID="ppoRemove_rdPnlInstanceID">
<Action ID="actDashboardRemovePanel" Type="Link" ConfirmMessage="Remove? Are you sure?">
<Target Type="Link" Link="javascript: LogiXML.Dashboard.pageDashboard.rdRemoveDashboardPanel('rdDashboardPanelID');" />
</Action>
</PopupOption>
within a Logi Analytics program.
I am using this XPATH:
<DefinitionModifier>
<SetAttribute XPath="//Action[#ID[starts-with(.,'ppoRemove_')]]" Caption="Remove###" />
</DefinitionModifier>
Do I use starts-with correctly (it currently does not work).
It seems that you meant to filter <Action> by ID of <PopupOption>. If this is the case, you can try following XPath :
//PopupOption[starts-with(#ID,'ppoRemove_')]/Action

Parsing XML file with nokogiri

I have the following xml file:
<?xml version='1.0' encoding='UTF-8'?>
<sparql xmlns='http://www.w3.org/2005/sparql-results#'>
<head>
<variable name='s'/>
</head>
<results>
<result>
<binding name='s'>
<uri>http://data.open.ac.uk/podcast/c9ddc42f6e1db95f59c83312d62da0ee</uri>
</binding>
</result>
<result>
<binding name='s'>
<uri>http://data.open.ac.uk/podcast/18873effb6c38ed83a7522ffb7c61c1b</uri>
</binding>
</result>
</results>
</sparql>
I want to get the uris from the document. I tried these commands:
doc = Nokogiri::XML(File.open("file.xml"))
doc.xpath("//uri")
but it returns nil.
However, if I modified the file to this:
<results>
<result>
<binding name='s'>
<uri>http://data.open.ac.uk/podcast/c9ddc42f6e1db95f59c83312d62da0ee</uri>
</binding>
</result>
<result>
<binding name='s'>
<uri>http://data.open.ac.uk/podcast/18873effb6c38ed83a7522ffb7c61c1b</uri>
</binding>
</result>
</results>
The above commands return the uris correctly.
You need to specify the namespace of the element you're trying to select. In the first document this is http://www.w3.org/2005/sparql-results#, inherited from the root-node. In the second document it works, because you're removed the namespace declaration by removing that root node.
The good news is because your namespace is defined in the root node Nokogiri will automatically register it for you, and you should be able to select the <uri> elements with
doc.xpath("//xmlns:uri")

Getting XML node matching XPath expression

I'm hoping you can help with this. I tried a number of XPath testers online and wasn't able to find a solution.
I'm trying to get the value of the first node with the '~tid' attribute from this XML:
<Response status="ok" version="1.1">
<Action>
<Page>
<Params>
<Param name="~tid" value="1345811517165"/>
<Param name="~action-type" value="DATA"/>
<Param name="~from-page" value="login"/>
<Param name="~from-act" value="submitData"/>
<Param name="login_USERNAME" value="" type="0"/>
<Param name="login_PASSWORD" value="" type="0"/>
</Params>
</Page>
<Data name="clientData" method="POST">
<Params>
<Param name="timezoneoffset" value=""/>
<Param name="daylightsavings" value=""/>
</Params>
</Data>
</Action>
<Action>
<Page>
<Params>
<Param name="~tid" value="1345811517165"/>
<Param name="~action-type" value="NAV"/>
<Param name="~from-page" value="login"/>
<Param name="~from-act" value="resetPassword"/>
<Param name="~to-page" value="login_resetPassword"/>
</Params>
</Page>
</Action>
<Action>
<Page>
<Params>
<Param name="~tid" value="1345811517165"/>
<Param name="~action-type" value="NAV"/>
<Param name="~from-page" value="login"/>
<Param name="~from-act" value="newUser"/>
<Param name="~to-page" value="login_newUser"/>
</Params>
</Page>
</Action>
</Response>
The XPath I'm using is:
//Params[1]/Param[#name='~tid']/#value
It gets all three values. How can I get just the first one?
Try
/descendant::Params[1]/Param[#name='~tid']/#value
From the W3C XPath specification:
NOTE: The location path //para[1] does not mean the same as the location path /descendant::para[1]. The latter selects the first descendant para element; the former selects all descendant para elements that are the first para children of their parents.
This is the second most FAQ in XPath.
Use:
(//Params/Param[#name='~tid'])[1]/#value
Or even:
(//Param[#name='~tid'])[1]/#value
Explanation:
The XPath pseudo-operator // has lower precedence (priority) than the [] operator.
The usual solution in any laguage when default priority needs to be overriden is to use brackets that explicitly specify the new, wanted priorities.

struts2 errors lost

I trying to use struts2 validation framework. I have a ActionName-validation.xml in place. Entry in the struts.xml is as follows
<action name="registerCandidateStep1" class="candidateAction"
method="registerCandidateStep1">
<result name="success" type="tiles">registerCandidate</result>
<result name="input" type="chain">
<param name="actionName">loadCandidateRegistrationForm</param>
<param name="namespace">/.secureActions</param>
</result>
</action>
<action name="loadCandidateRegistrationForm" class="loadCandidateFromAction"
method="loadCandidateRegistrationForm">
<result name="success" type="tiles">registerCandidate</result>
</action>
on error condition request do get forwarded to "loadCandidateRegistrationForm" but i dont see error on the page. I have included tag in the jsp
StrutsConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.objectFactory" value="spring" />
<constant name="struts.devMode" value="false" />
<constant name="struts.action.extension" value="action" />
<constant name="struts.custom.i18n.resources" value="global" />
<package name="org" namespace="/"
extends="struts-default,json-default">
<result-types>
<result-type name="tiles"
class="org.apache.struts2.views.tiles.TilesResult" />
</result-types>
<global-results>
<result name="welcome" type="tiles">welcome</result>
</global-results>
</package>
<package name="org.unsecureActions" extends="org">
<!--
This package contains such a actions which doesn't need user logged
in.
-->
<action name="welcome" method="forwardAction" class="baseAction">
<result name="success" type="tiles">welcome</result>
</action>
<action name="logout" method="logoutCandidate" class="logoutAction">
<result name="success" type="tiles">welcome</result>
</action>
<action name="loadAdvanceSearchForm" method="loadAdvanceSearch"
class="advanceSearchAction">
<result name="success" type="tiles">advanceSearch</result>
</action>
<!--Candidate workflow actions -->
<action name="registerCandidateStep1" class="candidateAction"
method="registerCandidateStep1">
<interceptor-ref name="store">
<param name="operationMode">STORE</param>
</interceptor-ref>
<interceptor-ref name="defaultStack" />
<result name="success" type="tiles">registerCandidate</result>
<result name="input" type="redirect">loadCandidateRegistrationForm.action</result>
</action>
<action name="registerCandidateStep2" class="candidateAction"
method="registerCandidateStep2">
<result name="success" type="tiles">registerCandidate</result>
<result name="input" type="tiles">loadCandidateRegistrationForm</result>
</action>
<action name="registerCandidateStep3" class="candidateAction"
method="registerCandidateStep3">
<result type="chain">
<param name="actionName">loginCandidate</param>
<param name="namespace">/org.unsecureActions</param>
</result>
<result name="input" type="tiles">registerCandidate</result>
</action>
<action name="loadCandidateRegistrationForm" class="loadCandidateFromAction"
method="loadCandidateRegistrationForm">
<interceptor-ref name="store">
<param name="operationMode">RETRIEVE</param>
</interceptor-ref>
<result name="success" type="tiles">registerCandidate</result>
</action>
<!--Candidate workflow actions -->
<action name="loginCandidate" class="loginAction" method="loginCandidate">
<result name="success" type="tiles">home</result>
<result name="input" type="tiles">welcome</result>
</action>
</package>
<package name="org.secureActions" extends="org">
<!--
This package contains such a actions which needs user must logged in
before executing these.
-->
<interceptors>
<!--
Following interceptor checks for is user logged in before executing
the action.
-->
<interceptor name="contextSecurityInterceptor"
class="org.kovid.matrimony.interceptor.ContextSecurityInterceptor">
</interceptor>
<!--
This stack is as like default stack provided ny Struts Only
difference is at the bottom of folowing stack where we included our
"contextSecurityInterceptor" interceptor.
-->
<interceptor-stack name="applicationStack">
<interceptor-ref name="exception" />
<interceptor-ref name="alias" />
<interceptor-ref name="servletConfig" />
<interceptor-ref name="prepare" />
<interceptor-ref name="i18n" />
<interceptor-ref name="chain" />
<interceptor-ref name="debugging" />
<interceptor-ref name="profiling" />
<interceptor-ref name="scopedModelDriven" />
<interceptor-ref name="modelDriven" />
<interceptor-ref name="fileUpload" />
<interceptor-ref name="checkbox" />
<interceptor-ref name="staticParams" />
<interceptor-ref name="actionMappingParams" />
<interceptor-ref name="params" />
<interceptor-ref name="conversionError" />
<interceptor-ref name="validation" />
<interceptor-ref name="workflow" />
<interceptor-ref name="contextSecurityInterceptor" />
</interceptor-stack>
</interceptors>
<!--
Setting default stack for interceptor taking care of this packageS.
-->
<default-interceptor-ref name="applicationStack" />
<action name="home" method="forwardAction" class="baseAction">
<result name="success" type="tiles">home</result>
</action>
<action name="loadAdvanceSearchForm" method="loadAdvanceSearch"
class="advanceSearchAction">
<result name="success" type="tiles">advanceSearch</result>
</action>
<action name="simpleSearch" method="simpleSearch" class="simpleSearchAction">
<result name="success" type="tiles">search</result>
<result name="input" type="tiles">home</result>
</action>
<action name="advanceSearch" method="advanceSearch" class="advanceSearchAction">
<result name="success" type="tiles">search</result>
</action>
<action name="loadImage" method="loadImage" class="imageAction">
<result name="imageData" type="stream">
<param name="contentType">${imageContentType}</param>
<param name="inputName">imageStream</param>
<param name="contentDisposition">filename="candidate.jpeg"</param>
<param name="bufferSize">${myBufferSize}</param>
</result>
</action>
</package>
</struts>
Action chaining is actively discouraged, and interactions with the validation interceptor is one reason why. You might be able to sneak around it by explicitly mapping some values (like the validation messages) from one action to the next, but... don't chain actions--there's almost never a reason to do so.
Like Dave said, Action Chaining is discouraged.
Action Chaining :
Don't Try This at Home
As a rule, Action Chaining is not recommended.
First explore other options, such as the Redirect After Post
technique.
And if you have good reason to use Redirect After Post, use the
Redirect Result + Message Store Interceptor OR
Redirect Action Result + Message Store Interceptor
Life time of Errors lasts for the current Action. If you forward/redirect to another action, then the errors will be lost.
Use session scope instead. Place ArrayList in session and append your errors/messages.
Action/Interceptor:
Map session = ActionContext.getContext().getSession();
List<String> errors = session.get("errorMessages");
if(errors==null)
session.put("errorMessages", errors=new ArrayList<String>() );
errors.add("Invalid Username/Password. Kindly retry");
JSP:
<s:iterator var="msg" value="#session.errorMessages" >
<p> ${msg} </p>
</s:iterator>
<s:set scope="session" var="errorMessages" value="%{null}" /><%--flush errors--%>

Resources