TLDR: I want to write an xpath expression to select all (at any level) children of parent node using both '..' and 'parent::', that will work in c# and javascript/typescript.
I am limited to xsd 1.0. I do not want to use preceding-sibling axis.
My xml looks like
<tns:s03.q01 id="s03.q01" text="Select the specific issues encountered (please select all that apply) and indicate the corresponding MBAs" description="" isAnsewerRequired="true" type="Question">
<tns:choices>
<tns:multiChoiceAssert condition="count(parent::tns:choices/*[@value='true']) = 0" message="'{$locator}\Choices' must have atleast one choice selected." relevantNodeLocator="string(../../@id)" />
<tns:s03.q01.c01 value="true" id="s03.q01.c01" text="Bias" description="" type="Choice">
<tns:selectMBAAssert condition="parent::*[@value='true'] and count(parent::*/tns:mba) = 0" message="'Select MBAs for {$locator}'." relevantNodeLocator="string(../@id)" />
<tns:selectValueAssert condition="parent::*[@value='false'] and count(parent::*/tns:mba) > 0" message="Select '{$locator}'." relevantNodeLocator="string(../@id)" />
<tns:mba>m1</tns:mba>
<tns:mba>m2</tns:mba>
</tns:s03.q01.c01>
<tns:s03.q01.c02 id="s03.q01.c02" text="Poor measurement quality" description="" type="Choice" value="false">
<tns:selectMBAAssert condition="parent::*[@value='true'] and count(parent::*/tns:mba) = 0" message="'Select MBAs for {$locator}'." relevantNodeLocator="string(../@id)" />
<tns:selectValueAssert condition="parent::*[@value='false'] and count(parent::*/tns:mba) > 0" message="Select '{$locator}'." relevantNodeLocator="string(../@id)" />
</tns:s03.q01.c02>
<tns:s03.q01.c03 id="s03.q01.c03" text="Statistically significant MUF" description="" type="Choice" value="false">
<tns:selectMBAAssert condition="parent::*[@value='true'] and count(parent::*/tns:mba) = 0" message="'Select MBAs for {$locator}'." relevantNodeLocator="string(../@id)" />
<tns:selectValueAssert condition="parent::*[@value='false'] and count(parent::*/tns:mba) > 0" message="Select '{$locator}'." relevantNodeLocator="string(../@id)" />
</tns:s03.q01.c03>
</tns:choices>
<tns:comment id="s03.q01.comment" title="Comments" description="If the answer to the previous questions is “Yes,” please provide the details, including the document type (initial DIQ, DIQ update, initial LOF information, LOF information update), facility/MBA code, the date due and the date received.">
<tns:s03.q01.comment dateRequested="2023-03-23" documentType="2" facility-mbaCode="m1" />
<tns:s03.q01.comment dateRequested="2023-04-24" documentType="4" facility-mbaCode="f2" />
</tns:comment>
</tns:s03.q01>
I am using c# and javascript and hence I am limited to xsd 1.0 I define validations using nodes like selectMBAAssert and selectValueAssert with rule in the 'condition' attribute. So while parsing the xml I select all nodes with @condition attribute and evaluate the condition in the context of the same node.
The code to do so works fine in c# which looks like
XmlDocument document = getDocumentWithSchema(xmlTextReader, schemaPath);//this is a method to load document with schema and xml.
ValidationEventHandler eventHandler = new ValidationEventHandler(ValidationEventHandler);
var nsmgr = new XmlNamespaceManager(document.NameTable);
nsmgr.AddNamespace("tns", "http://tempuri.org/XMLSchema2.xsd");
document.Validate(eventHandler);
//var nav = document.CreateNavigator();
var list = document.SelectNodes("//*[@condition]", nsmgr);
foreach (XmlNode node in list)
{
var condition = node.Attributes["condition"].Value;
var nodeNav = node.CreateNavigator();
var result = nodeNav.evaluateXPath(condition, nsmgr);
//If the condition is "//tns:choices" results contains 1 element.
if ((bool)result)
{
var errorMsg = node.Attributes["message"].Value;
var locator = node.Attributes["relevantNodeLocator"].Value;
var nodeLocator = nodeNav.evaluateXPath(locator, nsmgr);
errorMsg = errorMsg.Replace("{$locator}", nodeLocator.ToString());
Console.WriteLine($"Validation error:{errorMsg}");
}
}
However code in typescript does work the same way.
validateXML(questionId: any, xmlData: Document) {
var conditionNodes = xmlData.evaluate("//*[@id='" + questionId + "']/*[@condition]", xmlData.documentElement, null, XPathResult.ANY_TYPE, null);
var toretErrors: string = "";
try {
var currnetConditionNode: any = conditionNodes.iterateNext();
while (currnetConditionNode) {
//console.log(thisNode.textContent);
var atributeValue = currnetConditionNode.attributes["condition"].nodeValue;
var validationResult = xmlData.evaluate(atributeValue, currnetConditionNode, this.NSResolver, XPathResult.ANY_TYPE, null)
console.log(validationResult);
if (validationResult.booleanValue) {
toretErrors += currnetConditionNode.attributes["message"].nodeValue;
}
currnetConditionNode = conditionNodes.iterateNext();
}
}
catch (e) {
console.error('Error: Document parsing error ' + e);
}
return toretErrors;
}
NSResolver(nsPrefix) {
if (nsPrefix == "tns") {
return "http://tempuri.org/XMLSchema2.xsd";
}
return null;
}
How may i write the condition in selectMBAAssert node to select all (at any level) parent's children of type tns:mba?
Another question I think relevant to this question, are '..' and 'parent::' interchangeable? How may I script the condition attribute use both of them?
Sorry to make it lengthy question. Please let me know if you need any more details.
Via Active questions tagged javascript - Stack Overflow https://ift.tt/E1W2CjQ
Comments
Post a Comment