Skip to main content

XPath expression to select children of parent in xpath (that works in javascript and in c#)

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) &gt; 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) &gt; 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) &gt; 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

Popular posts from this blog

How to show number of registered users in Laravel based on usertype?

i'm trying to display data from the database in the admin dashboard i used this: <?php use Illuminate\Support\Facades\DB; $users = DB::table('users')->count(); echo $users; ?> and i have successfully get the correct data from the database but what if i want to display a specific data for example in this user table there is "usertype" that specify if the user is normal user or admin i want to user the same code above but to display a specific usertype i tried this: <?php use Illuminate\Support\Facades\DB; $users = DB::table('users')->count()->WHERE usertype =admin; echo $users; ?> but it didn't work, what am i doing wrong? source https://stackoverflow.com/questions/68199726/how-to-show-number-of-registered-users-in-laravel-based-on-usertype

Why is my reports service not connecting?

I am trying to pull some data from a Postgres database using Node.js and node-postures but I can't figure out why my service isn't connecting. my routes/index.js file: const express = require('express'); const router = express.Router(); const ordersCountController = require('../controllers/ordersCountController'); const ordersController = require('../controllers/ordersController'); const weeklyReportsController = require('../controllers/weeklyReportsController'); router.get('/orders_count', ordersCountController); router.get('/orders', ordersController); router.get('/weekly_reports', weeklyReportsController); module.exports = router; My controllers/weeklyReportsController.js file: const weeklyReportsService = require('../services/weeklyReportsService'); const weeklyReportsController = async (req, res) => { try { const data = await weeklyReportsService; res.json({data}) console...

How to split a rinex file if I need 24 hours data

Trying to divide rinex file using the command gfzrnx but getting this error. While doing that getting this error msg 'gfzrnx' is not recognized as an internal or external command Trying to split rinex file using the command gfzrnx. also install'gfzrnx'. my doubt is I need to run this program in 'gfzrnx' or in 'cmdprompt'. I am expecting a rinex file with 24 hrs or 1 day data.I Have 48 hrs data in RINEX format. Please help me to solve this issue. source https://stackoverflow.com/questions/75385367/how-to-split-a-rinex-file-if-i-need-24-hours-data