How to define and initialize variables in drools rule - java-8
I am using drools 6.1. I have a drool file. I want to do something like this.
import static com.softech.vu360.autoalert.util.Utility.getCurrentDate;
import static com.softech.vu360.autoalert.util.Utility.getDate;
import static com.softech.vu360.autoalert.util.Utility.getMonthNameFromInt;
import static com.softech.vu360.autoalert.util.Utility.getExpiryDate;
import static com.softech.vu360.autoalert.util.Utility.getEmailDate;
import static com.softech.vu360.autoalert.util.Utility.getWeekOfYear;
import com.softech.vu360.autoalert.model.LicenseCredential;
import com.softech.vu360.autoalert.model.Learner;
import com.softech.vu360.autoalert.CsvFileWriter;
import java.time.LocalDate;
import java.util.Date;
global com.softech.vu360.autoalert.CsvFileWriter learnerCsvFileWriter;
function void processData(LicenseCredential licenseCredential, CsvFileWriter learnerCsvFileWritern, LocalDate expiryDate, LocalDate emailDate){
Learner learner = new Learner();
learner.setFirstName(licenseCredential.getFirstName());
...
learnerCsvFileWriter.add(learner);
}
rule "Renewal alert for 60 days"
when
licenseCredential : LicenseCredential()
$courseCompletionDate : licenseCredential.getCourseCompletionDate()
$renewalDeadlineDay : licenseCredential.getRenewalDeadlineDay()
$renewalDeadlineMonth : licenseCredential.getRenewalDeadlineMonth()
$currentDate : getCurrentDate()
$dayOfMonth : $courseCompletionDate.getDate()
$month : $courseCompletionDate.getMonth()
$expiryDate : getExpiryDate(licenseCredential)
$emailDate : getEmailDate(2, licenseCredential)
$localDate : LocalDate.now()
$intRenewalDeadlineDay : Integer.valueOf($renewalDeadlineDay)
$intRenewalDeadlineMonth : Integer.valueOf($renewalDeadlineMonth)
(
eval($renewalDeadlineDay == "0" && $renewalDeadlineMonth == "0") &&
eval($currentDate.after(getDate(2, $dayOfMonth, $month + 1))) &&
eval($currentDate.before(getDate(1, $dayOfMonth, $month + 1 ))) &&
eval(getWeekOfYear($localDate.toString()) == getWeekOfYear($emailDate.toString()))
) ||
(
eval($currentDate.after(getDate(2, $intRenewalDeadlineDay, $intRenewalDeadlineMonth))) &&
eval($currentDate.before(getDate(1, $intRenewalDeadlineDay, $intRenewalDeadlineMonth))) &&
eval(getWeekOfYear($localDate.toString()) == getWeekOfYear($emailDate.toString()))
)
then
System.out.println("Rule For 60 Days Called");
processData(licenseCredential, learnerCsvFileWriter, $expiryDate, $emailDate);
end
I want to declare local variables in my loop. LicenseCredential is a list basically. When I run this rule I get errors that
text=Unable to resolve ObjectType 'licenseCredential.getCourseCompletionDate'], Message [id=2, level=ERROR, path=drools/rules/Rule.drl, line=71, column=0
text=Unable to resolve ObjectType 'licenseCredential.getRenewalDeadlineDay'], Message [id=3, level=ERROR, path=drools/rules/Rule.drl, line=72, column=0
text=Unable to resolve ObjectType 'licenseCredential.getRenewalDeadlineMonth'], Message [id=4, level=ERROR, path=drools/rules/Rule.drl, line=73, column=0
text=Unable to resolve ObjectType 'getCurrentDate'], Message [id=5, level=ERROR, path=drools/rules/Rule.drl, line=74, column=0
text=Unable to resolve ObjectType '$courseCompletionDate.getDate'], Message [id=6, level=ERROR, path=drools/rules/Rule.drl, line=75, column=0
text=Unable to resolve ObjectType '$courseCompletionDate.getMonth'], Message [id=7, level=ERROR, path=drools/rules/Rule.drl, line=76, column=0
text=Unable to resolve ObjectType 'getExpiryDate'], Message [id=8, level=ERROR, path=drools/rules/Rule.drl, line=77, column=0
text=Unable to resolve ObjectType 'getEmailDate'], Message [id=9, level=ERROR, path=drools/rules/Rule.drl, line=78, column=0
text=Unable to resolve ObjectType 'LocalDate.now'], Message [id=10, level=ERROR, path=drools/rules/Rule.drl, line=79, column=0
text=Unable to resolve ObjectType 'Integer.valueOf'], Message [id=11, level=ERROR, path=drools/rules/Rule.drl, line=80, column=0
text=Unable to resolve ObjectType 'Integer.valueOf'], Message [id=12, level=ERROR, path=drools/rules/Rule.drl, line=36, column=0
If i put semicolon at the end of each variable like
$courseCompletionDate : licenseCredential.getCourseCompletionDate();
$renewalDeadlineDay : licenseCredential.getRenewalDeadlineDay();
$renewalDeadlineMonth : licenseCredential.getRenewalDeadlineMonth();
$currentDate : getCurrentDate();
$dayOfMonth : $courseCompletionDate.getDate();
$month : $courseCompletionDate.getMonth();
$expiryDate : getExpiryDate(licenseCredential);
$emailDate : getEmailDate(2, licenseCredential);
$localDate : LocalDate.now();
$intRenewalDeadlineDay : Integer.valueOf($renewalDeadlineDay);
$intRenewalDeadlineMonth : Integer.valueOf($renewalDeadlineMonth);
and run the rule I get errors that
$renewalDeadlineDay cannot be resolved to a variable
$renewalDeadlineMonth cannot be resolved to a variable
$currentDate cannot be resolved
$dayOfMonth cannot be resolved to a variable
$month cannot be resolved to a variable
$currentDate cannot be resolved
$dayOfMonth cannot be resolved to a variable
$month cannot be resolved to a variable
$localDate cannot be resolved
$emailDate cannot be resolved
$currentDate cannot be resolved
$intRenewalDeadlineDay cannot be resolved to a variable
$intRenewalDeadlineMonth cannot be resolved to a variable
$currentDate cannot be resolved
$intRenewalDeadlineDay cannot be resolved to a variable
$intRenewalDeadlineMonth cannot be resolved to a variable
$localDate cannot be resolved
$emailDate cannot be resolved
$expiryDate cannot be resolved to a variable
$emailDate cannot be resolved to a variable], Message [id=14, level=ERROR, path=drools/rules/Rule.drl, line=-1, column=0
How can I define local variables. How can I do this ?
Thanks
---------------------------------
Edit
Here how I am firing rules
List<LicenseCredential> objectList = dao.select();
BusinessRuleProcessor ruleProcessor = (BusinessRuleProcessor)context.getBean("businessRuleProcessor");
ruleProcessor.configureAndApplyRulesOnObject(objectList);
public class BusinessRuleProcessor {
....
public void configureAndApplyRulesOnObject(List<LicenseCredential> objectList){
statelessKieSession.setGlobal("learnerCsvFileWriter", csvFileWriter);
statelessKieSession.execute(objectList);
}
}
--------------
Edit2:
Tried this and getting errors
rule "Renewal alert for 60 days"
when
licenseCredential : LicenseCredential()
$licenseCredentialCC : LicenseCredential($courseCompletionDate : courseCompletionDate)
$licenseCredentialRDLD : LicenseCredential($renewalDeadlineDay : renewalDeadlineDay)
$licenseCredentialRDLM : LicenseCredential($renewalDeadlineMonth : renewalDeadlineMonth)
$licenseCredentialCD : LicenseCredential($currentDate : getCurrentDate())
$licenseCredentialDOM : LicenseCredential($dayOfMonth : $licenseCredentialCC.getDate())
$licenseCredentialM : LicenseCredential($month : $licenseCredentialCC.getMonth())
$licenseCredentialEXD : LicenseCredential($expiryDate : getExpiryDate(licenseCredential))
$licenseCredentialEMD : LicenseCredential($emailDate : getEmailDate(2, licenseCredential))
$licenseCredentialLD : LicenseCredential($localDate : LocalDate.now())
$licenseCredentialIRDLD : LicenseCredential($intRenewalDeadlineDay : Integer.valueOf($licenseCredentialRDLD))
$licenseCredentialIRDLM : LicenseCredential($intRenewalDeadlineMonth : Integer.valueOf($licenseCredentialRDLM))
(
eval($renewalDeadlineDay == "0" && $renewalDeadlineMonth == "0") &&
eval($currentDate.after(getDate(2, $dayOfMonth, $month + 1))) &&
eval($currentDate.before(getDate(1, $dayOfMonth, $month + 1 ))) &&
eval(getWeekOfYear($localDate.toString()) == getWeekOfYear($emailDate.toString()))
) ||
(
eval($currentDate.after(getDate(2, $intRenewalDeadlineDay, $intRenewalDeadlineMonth))) &&
eval($currentDate.before(getDate(1, $intRenewalDeadlineDay, $intRenewalDeadlineMonth))) &&
eval(getWeekOfYear($localDate.toString()) == getWeekOfYear($emailDate.toString()))
)
then
System.out.println("Rule For 60 Days Called");
processData(licenseCredential, learnerCsvFileWriter, $expiryDate, $emailDate);
end
Errors:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'autoalert-ksession-stateless': Cannot resolve reference to bean 'autoalert-kbase' while setting bean property 'kBase'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'autoalert-kbase': Invocation of init method failed; nested exception is java.lang.RuntimeException: Error while creating KieBase[Message [id=1, level=ERROR, path=drools/rules/Rule.drl, line=76, column=0
text=Unable to Analyse Expression $licenseCredentialCC.getDate():
[Error: unable to resolve method using strict-mode: com.softech.vu360.autoalert.model.LicenseCredential.getDate()]
[Near : {... $licenseCredentialCC.getDate() ....}]
^
[Line: 76, Column: 2]], Message [id=2, level=ERROR, path=drools/rules/Rule.drl, line=76, column=0
text=Unable to analyze expression '$licenseCredentialCC.getDate()'], Message [id=3, level=ERROR, path=drools/rules/Rule.drl, line=77, column=0
text=Unable to Analyse Expression $licenseCredentialCC.getMonth():
[Error: unable to resolve method using strict-mode: com.softech.vu360.autoalert.model.LicenseCredential.getMonth()]
[Near : {... $licenseCredentialCC.getMonth() ....}]
^
[Line: 77, Column: 2]], Message [id=4, level=ERROR, path=drools/rules/Rule.drl, line=77, column=0
text=Unable to analyze expression '$licenseCredentialCC.getMonth()'], Message [id=5, level=ERROR, path=drools/rules/Rule.drl, line=78, column=0
text=Variables can not be used inside bindings. Variable [licenseCredential] is being used in binding 'getExpiryDate(licenseCredential)'], Message [id=6, level=ERROR, path=drools/rules/Rule.drl, line=79, column=0
text=Variables can not be used inside bindings. Variable [licenseCredential] is being used in binding 'getEmailDate(2, licenseCredential)'], Message [id=7, level=ERROR, path=drools/rules/Rule.drl, line=81, column=0
text=Unable to Analyse Expression Integer.valueOf($licenseCredentialRDLD):
[Error: unable to resolve method using strict-mode: java.lang.Integer.valueOf(com.softech.vu360.autoalert.model.LicenseCredential)]
[Near : {... Integer.valueOf($licenseCredentialRDLD ....}]
^
[Line: 81, Column: 2]], Message [id=8, level=ERROR, path=drools/rules/Rule.drl, line=81, column=0
text=Unable to analyze expression 'Integer.valueOf($licenseCredentialRDLD)'], Message [id=9, level=ERROR, path=drools/rules/Rule.drl, line=82, column=0
text=Unable to Analyse Expression Integer.valueOf($licenseCredentialRDLM):
[Error: unable to resolve method using strict-mode: java.lang.Integer.valueOf(com.softech.vu360.autoalert.model.LicenseCredential)]
[Near : {... Integer.valueOf($licenseCredentialRDLM ....}]
^
[Line: 82, Column: 2]], Message [id=10, level=ERROR, path=drools/rules/Rule.drl, line=82, column=0
text=Unable to analyze expression 'Integer.valueOf($licenseCredentialRDLM)'], Message [id=11, level=ERROR, path=drools/rules/Rule.drl, line=60, column=0
text=[ function processDataprocessData (line:60): learnerCsvFileWriter cannot be resolved
]], Message [id=12, level=ERROR, path=drools/rules/Rule.drl, line=68, column=0
text=Rule Compilation error The import drools.rules.ProcessData cannot be resolved
The operator + is undefined for the argument type(s) Object, int
The operator + is undefined for the argument type(s) Object, int
The method getDate(int, int, int) in the type Utility is not applicable for the arguments (int, Object, Object)
The method getDate(int, int, int) in the type Utility is not applicable for the arguments (int, Object, Object)
$expiryDate cannot be resolved to a variable
$emailDate cannot be resolved to a variable], Message [id=13, level=ERROR, path=drools/rules/Rule.drl, line=-1, column=0
Edit 3
rule "Renewal alert for 60 days"
when
licenseCredential : LicenseCredential()
$licenseCredential1 : LicenseCredential($courseCompletionDate : courseCompletionDate)
$licenseCredential2 : LicenseCredential($renewalDeadlineDay : renewalDeadlineDay)
$licenseCredential3 : LicenseCredential($renewalDeadlineMonth : renewalDeadlineMonth)
$licenseCredential4 : LicenseCredential($currentDate : getCurrentDate())
//$licenseCredential5 : LicenseCredential($dayOfMonth : licenseCredential.getCourseCompletionDate().getDate())
//$licenseCredential6 : LicenseCredential($month : licenseCredential.getCourseCompletionDate().getMonth())
//$licenseCredential7 : LicenseCredential($expiryDate : getExpiryDate(licenseCredential))
//$licenseCredential8 : LicenseCredential($emailDate : getEmailDate(2, licenseCredential))
$licenseCredential9 : LicenseCredential($localDate : LocalDate.now())
(
eval($renewalDeadlineDay == "0" && $renewalDeadlineMonth == "0") &&
eval($currentDate.after(getDate(2, licenseCredential.getCourseCompletionDate().getDate(), licenseCredential.getCourseCompletionDate().getMonth() + 1))) &&
eval($currentDate.before(getDate(1, licenseCredential.getCourseCompletionDate().getDate(), licenseCredential.getCourseCompletionDate().getMonth() + 1 ))) &&
eval(getWeekOfYear($localDate.toString()) == getWeekOfYear(getEmailDate(2, licenseCredential).toString()))
) ||
(
eval($currentDate.after(getDate(2, Integer.valueOf($renewalDeadlineDay), Integer.valueOf($renewalDeadlineMonth)))) &&
eval($currentDate.before(getDate(1, Integer.valueOf($renewalDeadlineDay), Integer.valueOf($renewalDeadlineMonth)))) &&
eval(getWeekOfYear($localDate.toString()) == getWeekOfYear(getEmailDate(2, licenseCredential).toString()))
)
then
System.out.println("Rule For 60 Days Called");
processData(licenseCredential, learnerCsvFileWriter, 2);
end
------------------
Edit 4
Here is my LicenseCredential class
public class LicenseCredential {
private String learnerName;
protected String firstName;
protected String lastName;
protected String learnerEmailAddress;
private String userGUID;
private Integer vu360UserId;
private Integer courseId;
protected String courseName;
protected Date courseCompletionDate;
private Integer credentialId;
protected String officialLicenseName;
private String shortLicenseName;
private String renewalDeadLineType;
private String renewalFrequency;
private String renewalDeadlineDay;
private String renewalDeadlineMonth;
private String hardDeadLineYear;
private String staggeredBy;
private String staggeredTo;
protected String jurisdiction;
protected String storefrontURL;
// setters and getters
}
Here is my Utility class
public class Utility {
public static Date getDate(int monthsToBeSubtracted, int date, int month) throws Exception{
Calendar c = Calendar.getInstance();
c.set(Calendar.MONTH, month-1);
c.set(Calendar.DATE, date);
c.set(Calendar.MONTH, c.get(Calendar.MONTH)-monthsToBeSubtracted);
c.set(Calendar.YEAR, getCurrentDate().getYear()+1900);
return c.getTime();
}
public static Date getCurrentDate(){
Calendar c = Calendar.getInstance();
return c.getTime();
}
public static int getWeekOfYear(String date) throws Exception{
Date currentDate = new SimpleDateFormat("yyyy-MM-dd").parse(date);
String weekOfYear = new SimpleDateFormat("w").format(currentDate);
return Integer.valueOf(weekOfYear);
}
public static LocalDate getExpiryDate(LicenseCredential licenseCredential) {
if (licenseCredential.getRenewalDeadlineDay() == "0" && licenseCredential.getRenewalDeadlineMonth() == "0") {
Date courseCompletionDate = licenseCredential.getCourseCompletionDate();
...
return expiryDate;
} else {
...
return expiryDate;
}
}
}
Previously this rule was like this
rule "Renewal alert for 60 days"
when
licenseCredential : LicenseCredential()
(
eval(licenseCredential.getRenewalDeadlineDay() == "0" && licenseCredential.getRenewalDeadlineMonth() == "0") &&
eval(getCurrentDate().after(getDate(2, licenseCredential.getCourseCompletionDate().getDate(), licenseCredential.getCourseCompletionDate().getMonth()+1))) &&
eval(getCurrentDate().before(getDate(1, licenseCredential.getCourseCompletionDate().getDate(), licenseCredential.getCourseCompletionDate().getMonth()+1)))
) ||
(
eval(getCurrentDate().after(getDate(2, Integer.valueOf(licenseCredential.getRenewalDeadlineDay()), Integer.valueOf(licenseCredential.getRenewalDeadlineMonth()) ))) &&
eval(getCurrentDate().before(getDate(1, Integer.valueOf(licenseCredential.getRenewalDeadlineDay()), Integer.valueOf(licenseCredential.getRenewalDeadlineMonth() ))))
)
then
System.out.println("Rule For 60 Days Called");
processData(licenseCredential, "templates/Template.vm", "60Days", messageProducer);
end
While I don't know what the rule should evaluate, this is more like the style your rule should be written. I don't know how LicenseCredential is declared, nor do I know those Util.getXyz functions, so this may not work. Also, I've skipped the last condition.
rule "Renewal alert for 60 days"
when
licenseCredential : LicenseCredential(
$courseCompletionDate : courseCompletionDate,
$renewalDeadlineDay : renewalDeadlineDay == "0",
$renewalDeadlineMonth : renewalDeadlineMonth == "0",
$currentDate : currentDate after
getDate(2, $courseCompletionDate.getDate(),
$courseCompletionDate.getMonth()+1 ),
&& before
getDate(1, $courseCompletionDate.getDate(),
$courseCompletionDate.getMonth()+1 ) )
then
System.out.println("Rule For 60 Days Called");
processData(licenseCredential, learnerCsvFileWriter, 2);
end
Related
Spring, How to set error message from custom constraint validator at runtime
I have this constraint for validating dhcp host addresses. annotation class DHCPAddressConstraint( val message: String = "Invalid dhcp address.", val groups: Array<KClass<*>> = [], val payload: Array<KClass<out Payload>> = [], val cidrField: String = "", val addressRangeField: String = "" ) class DHCPAddressValidator: ConstraintValidator<DHCPAd, Any> { override fun isValid(obj: Any, context: ConstraintValidatorContext): Boolean { val cidr = ReflectionUtils.get(obj, cidrField) val addressRange = ReflectionUtils.get(obj, addressRangeField) return isValidCIDR(cidr) && isValidAdressRange(cidr, addressRange) } } So if something is invalid it would return just "Invalid dhcp address.". I want to set the error message to be more specific so why is it invalid. For example the dhcp address range may not be in the CIDR range or the user enters reserved IP address and so on. I expect to have error message like this "Invalid dhcp address due to ${reason}". how can I set the constraint error message at runtime?
you could take help of #ControllerAdvice & #ExceptionHandler Please look at the example code below #RestControllerAdvice public class ApiExceptionController { #ExceptionHandler(value = PageNotFoundApiException.class) public ResponseEntity<Object> pageNotFoundApiException(PageNotFoundApiException exception){ return new ResponseEntity<>("Page Not Found 404", HttpStatus.NOT_FOUND); } } You can also take a reference over this documentation I hope, it helps!
ERROR : syntax error, unexpected '$app' (T_VARIABLE), expecting ')'
Found in [consoletvs\charts\src\ChartsServiceProvider.php] Error Found this error.. any ideas ?
The error is very clear, it tells you that you are missing one ) after your $app variable. Try this : public function register(): void { $this->app->singleton(Registrar::class, fn(Application $app)) => new Registrar ( //... ); }
org.hibernate.QueryException: Expected positional parameter count: 1, actual parameters: [] [CALL usp_LoginDetails(?, :p_login)]
I am trying my best but i am not able to resolve this error please help me. DaoImplimentation file: #Override public LoginProcedure getLoginProcedureByNamedQuery(String p_login) { try { Query lquery = getHibernateTemplate().getSessionFactory().openSession().getNamedQuery("dd"); lquery.setParameter("p_login", p_login); List ll= lquery.list(); System.out.println("value of ll"+ll); } }catch(Exception e){ e.printStackTrace(); } return null; } Hbm file : <![CDATA[CALL usp_LoginDetails(?, :p_login)]]> </sql-query> Error coming : 2015-09-18 18:06:05,769 ERROR [stderr] (default task-31) org.hibernate.QueryException: Expected positional parameter count: 1, actual parameters: [] [CALL usp_LoginDetails(?, :p_login)]
On your hbml file can you try the following syntax: <sql-query callable="true" name="dd">{call usp_LoginDetails(:p_login)} <query-param name="p_login" type="string"/> </sql-query>
Uncaught Error: Syntax error, unrecognized expression: option[]
When I try to add a selector and then pick an option, the script errors. <form:select propertyContainer="${searchCriteria}" id="macroconditions" liveSearch="true" name="macroconditions" propertyPath="macroconditions" convertsToAccordion="true"/> The log shows: Uncaught Error: Syntax error, unrecognized expression: option[value=text of the selector] SearchCriteria Script: private EclMacroconditionCollection macroconditions; public EclMacroconditionCollection getMacroconditions() { if (macroconditions == null){ macroconditions = new EclMacroconditionCollection(EclMacrocondition.class); Object period = getValueFromCookie(getPeriod()); macroconditions.getMacroconditions(period == null ? null : period.toString()); } return macroconditions; } public void setMacroconditions(EclMacroconditionCollection macroconditions) { this.macroconditions = macroconditions; } thanks
dom4j makeElement with # xpath, but asXML result can not be parsed by Oracle extractvalue function
I'm working on an XML message process program using dom4j, and encounter a problem with XML node attribute parsing. The business requirement is: parse and validate input XML, if a field or an attribute is invalid, return an XML which structure denotes the error. And I'v snipped a test program below: import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.Node; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class XPathStudy { private final static Logger log = LoggerFactory.getLogger(XPathStudy.class); private static String xmlInput; private static void initXmlInput() { xmlInput = "<RootTag> <BizRec FLAG=\"5\">"; xmlInput += " <FieldOne>11111</FieldOne>"; xmlInput += " <FieldTwo></FieldTwo>"; xmlInput += " <FieldThree>33333</FieldThree>"; xmlInput += " </BizRec> </RootTag>"; } private static Document makeErrRspsDoc(String xpath, String errCode, String errDesc) { Document errDoc = DocumentHelper.createDocument(); Element errElem = DocumentHelper.makeElement(errDoc, xpath); errElem.addElement("ErrCode").addText(errCode); errElem.addElement("ErrDesc").addText(errDesc); return errDoc; } public static void main(String[] args) throws Exception { initXmlInput(); log.info("xmlInput = " + xmlInput); Document doc = DocumentHelper.parseText(xmlInput); log.info("xmlInput parsed done"); String xpath = "*//FieldTwo"; Node node = doc.getRootElement().selectSingleNode(xpath); if (node == null) { log.warn("node [" + xpath + "] not found"); System.exit(1); } log.info("node [" + node.getPath() + "] located"); if (node.getText().trim().isEmpty()) { Document errDoc = makeErrRspsDoc(node.getPath(), "1201", "FieldTwo can not be empty"); log.warn("errDoc: " + errDoc.asXML()); } else { log.info("FieldTwo validation ok"); } xpath = "*//#FLAG"; node = doc.getRootElement().selectSingleNode(xpath); if (node == null) { log.warn("node [" + xpath + "] not found"); System.exit(1); } log.info("node [" + node.getPath() + "] located"); int flagVal = Integer.parseInt(node.getText().trim()); if (flagVal == 1 || flagVal == 2) { log.info("FLAG " + flagVal + " is ok"); } else { Document errDoc = makeErrRspsDoc(node.getPath(), "1001", "FLAG attr should be 1 or 2"); log.warn("errDoc: " + errDoc.asXML()); } } } And run it, the log info below: 15:01:08.143 [main] INFO XPathStudy - xmlInput = <RootTag> <BizRec FLAG="5"> <FieldOne>11111</FieldOne> <FieldTwo></FieldTwo> <FieldThree>33333</FieldThree> </BizRec> </RootTag> 15:01:08.203 [main] INFO XPathStudy - xmlInput parsed done 15:01:08.255 [main] INFO XPathStudy - node [/RootTag/BizRec/FieldTwo] located 15:01:08.259 [main] WARN XPathStudy - errDoc: <?xml version="1.0" encoding="UTF-8"?> <RootTag><BizRec><FieldTwo><ErrCode>1201</ErrCode><ErrDesc>FieldTwo can not be empty</ErrDesc></FieldTwo></BizRec></RootTag> 15:01:08.260 [main] INFO XPathStudy - node [/RootTag/BizRec/#FLAG] located 15:01:08.260 [main] WARN XPathStudy - errDoc: <?xml version="1.0" encoding="UTF-8"?> <RootTag><BizRec><#FLAG><ErrCode>1001</ErrCode><ErrDesc>FLAG attr should be 1 or 2</ErrDesc></#FLAG></BizRec></RootTag> Everything seems ok, and the errDoc will be logged to an Oracle10g table (a VARCHAR2(1000) field), the following SQL is ok: select extractvalue(xmltype('<RootTag><BizRec><FieldTwo><ErrCode>1201</ErrCode><ErrDesc>FieldTwo can not be empty</ErrDesc></FieldTwo></BizRec></RootTag>'), '*//ErrCode') as err_code from dual; 1201 But this SQL will fail: select extractvalue(xmltype('<RootTag><BizRec><#FLAG><ErrCode>1001</ErrCode><ErrDesc>FLAG attribute should be 1 or 2</ErrDesc></#FLAG></BizRec></RootTag>'), '*//ErrCode') as err_code from dual; Error starting at line 1 in command: select extractvalue(xmltype('<RootTag><BizRec><#FLAG><ErrCode>1001</ErrCode><ErrDesc>FLAG attribute should be 1 or 2</ErrDesc></#FLAG></BizRec></RootTag>'), '*//ErrCode') as err_code from dual Error report: SQL Error: ORA-31011: XML parsing failed ORA-19202: Error occurred in XML processing LPX-00231: invalid character 64 ('#') found in a Name or Nmtoken Error at line 1 ORA-06512: at "SYS.XMLTYPE", line 301 ORA-06512: at line 1 31011. 00000 - "XML parsing failed" *Cause: XML parser returned an error while trying to parse the document. *Action: Check if the document to be parsed is valid. And Oracle's doc explains that XML's node can not contain special chars. So, my question is: howto change my Java code to solve the problem of the 'FLAG' attribute's error response?
<#FLAG> is not a legal XML element name, since the # character cannot be the start of a name. DOM4J is not known for being best in class when it comes to enforcing well formed and valid XML documents. To communicate the failing node as an XPath expression, consider storing it in an attribute or as a text node.