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

Prop `className` did not match in next js app

I have written a sample code ( Github Link here ). this is a simple next js app, but giving me error when I refresh the page. This seems to be the common problem and I tried the fix provided in the internet but does not seem to fix my issue. The error is Warning: Prop className did not match. Server: "MuiBox-root MuiBox-root-1" Client: "MuiBox-root MuiBox-root-2". Did changes for _document.js, modified _app.js as mentioned in official website and solutions in stackoverflow. but nothing seems to work. Could someone take a look and help me whats wrong with the code? Via Active questions tagged javascript - Stack Overflow https://ift.tt/2FdjaAW

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