XPath 表达式,用于在 xpath 中选择父级的子级(适用于 javascript 和 c#)

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

提问人:Raviraj Bhalerao 提问时间:9/16/2023 更新时间:9/16/2023 访问量:43

问:

TLDR:我想编写一个 xpath 表达式,以使用 '..' 和 'parent::' 选择父节点的所有(在任何级别)子节点,这将在 c# 和 javascript/typescript 中工作。

我仅限于 xsd 1.0。我不想使用前面的同级轴。

我的xml看起来像

    <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>

我正在使用 c# 和 javascript,因此我仅限于 xsd 1.0 我使用 selectMBAAssert 和 selectValueAssert 等节点定义验证,并在“condition”属性中使用规则。因此,在解析 xml 时,我选择所有具有 @condition 属性的节点,并在同一节点的上下文中评估条件。

这样做的代码在 c# 中工作正常,如下所示

            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}");
                }

            }

但是,打字稿中的代码确实以相同的方式工作。

  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;
  }

如何在 selectMBAAssert 节点中编写条件以选择所有(在任何级别)父级的 tns:mba 类型的子项?

我认为与这个问题相关的另一个问题是,“..”和“parent::”可以互换吗?如何使用它们来编写条件属性的脚本?

很抱歉让它变得冗长。如果您需要更多详细信息,请告诉我。

JavaScript C# XML XPath

评论

0赞 forty-two 9/16/2023
..只是 的简写,所以它们应该是可以互换的parent::
1赞 Martin Honnen 9/16/2023
不清楚你想实现什么,为什么你想同时使用和?XSD与此有什么关系?..parent::
0赞 Michael Kay 9/16/2023
首先,我认为当你说 XSD 1.0 时,你可能指的是 XPath 1.0。其次,如果你要加入人为的约束,比如同时使用“..”和“parent::node()”(它们是同义词),那么你需要解释为什么。
0赞 Michael Kay 9/16/2023
当你说“所有(任何级别的)孩子”时,你让每个人都感到困惑。“子女”是指直系子女;如果你想下降到任何级别,你说的是“后代”。
0赞 Raviraj Bhalerao 9/16/2023
谢谢大家的评论。

答: 暂无答案