You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6下如何让XML的condition属性引用当前Car节点的year属性

问题与解决方案

场景说明

使用.NET 6解析XML文件,由于.NET 6不支持XSD 1.1的xs:assert,通过XPath选中所有带condition属性的sg:Car节点,遍历并评估属性内的表达式是否为true。

XML文件内容:

<?xml version="1.0" encoding="utf-8"?>
<sg:EmployeeDetails xmlns:sg="http://sg.iaea.org/ssac-qs/qsSchema.xsd">
    <sg:FirstName>Sagar</sg:FirstName>
    <sg:MiddleName>H</sg:MiddleName>
    <sg:LastName>Shinde</sg:LastName>
    <sg:EmailId>sagarharidasshinde@gmail.com</sg:EmailId>
    <sg:Mobile>9021063389</sg:Mobile>
    <sg:Years>
        <sg:Year>1954</sg:Year>
        <sg:Year>1980</sg:Year>
        <sg:Year>1954</sg:Year>
    </sg:Years>
    <sg:Address>135/214, Hindustan Chowk, Mulund Colony, Mulund (W) - 400082</sg:Address>
    <sg:Cars>
        <sg:Car id="car1" year="1980"  condition="count(./ancestor::sg:EmployeeDetails/sg:Years/sg:Year[text() = //sg:Car[@id='car1']/@year]) &gt;=0" message="Driver must be 100 yrs old.">BMW</sg:Car>
        <sg:Car id="car2" year="1954" condition="count(./ancestor::sg:EmployeeDetails/sg:Years/sg:Year[text() = //sg:Car[@id='car1']/@year]) &gt;=0" message="Driver must be 100 yrs old.">BMW</sg:Car>
    </sg:Cars>
</sg:EmployeeDetails>

用于解析和验证的C#代码:

string xmlFilePath = "input.xml";
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas.Add("http://sg.iaea.org/ssac-qs/qsSchema.xsd", "input.xsd"); 
settings.ValidationType = ValidationType.Schema;
ValidationEventHandler eventHandler = new ValidationEventHandler(ValidationEventHandler);

using (XmlReader reader = XmlReader.Create(xmlFilePath, settings))
{
    XmlDocument document = new XmlDocument();
    document.Load(reader);
    
    var nsmgr = new XmlNamespaceManager(document.NameTable);
    nsmgr.AddNamespace("sg", "http://sg.iaea.org/ssac-qs/qsSchema.xsd");

    document.Validate(eventHandler);
    // 读取XML内容并验证Schema

    var nav = document.CreateNavigator();
    var list = nav.Select("//sg:Car[@condition]", nsmgr);
    while(list.MoveNext())
    {
        var item = list.Current;
        var condition = item.GetAttribute("condition", "");
        var result = item.Evaluate(condition, nsmgr);
        if (!(bool)result)
        {
            Console.WriteLine($"Validation error: {item.GetAttribute("message", "")}");
        }
    }
}

// 验证事件处理函数
private static void ValidationEventHandler(object sender, ValidationEventArgs e)
{
    switch (e.Severity)
    {
        case XmlSeverityType.Error:
            Console.WriteLine($"Schema Error: {e.Message}");
            break;
        case XmlSeverityType.Warning:
            Console.WriteLine($"Schema Warning: {e.Message}");
            break;
    }
}

需求与问题

需要设置condition属性值,判断当前sg:Car节点的year属性值是否存在于其祖先sg:EmployeeDetails下的sg:Years/sg:Year元素中。当前表达式硬编码了特定Car节点的ID(如//sg:Car[@id='car1']),希望改为动态引用当前Car节点的year属性,但直接使用@year会在sg:Year节点上下文查找该属性,导致表达式执行失败。

解决方案

使用XPath的current()函数来指代当前正在评估的sg:Car节点。在谓词(方括号)内,上下文会切换到sg:Year节点,current()可以保留最初的Car节点上下文,从而正确获取其year属性。

正确的condition表达式如下(XML中需转义大于号>为&gt;):

count(./ancestor::sg:EmployeeDetails/sg:Years/sg:Year[text() = current()/@year]) &gt;= 0

修改后的XML中Car节点示例:

<sg:Car id="car1" year="1980" condition="count(./ancestor::sg:EmployeeDetails/sg:Years/sg:Year[text() = current()/@year]) &gt;=0" message="Driver must be 100 yrs old.">BMW</sg:Car>
<sg:Car id="car2" year="1954" condition="count(./ancestor::sg:EmployeeDetails/sg:Years/sg:Year[text() = current()/@year]) &gt;=0" message="Driver must be 100 yrs old.">BMW</sg:Car>

原理说明

  • 在XPath 1.0中,current()函数返回的是当前正在处理的节点(即执行Evaluate方法时的sg:Car节点)。
  • 当遍历到sg:Year节点的谓词内时,上下文变为sg:Year,此时@year会指向sg:Year的属性(不存在),而current()/@year则会指向外层的sg:Car节点的year属性,从而实现正确的对比。

补充信息

对应的XSD文件:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
        targetNamespace="http://sg.iaea.org/ssac-qs/qsSchema.xsd"
        xmlns:sg="http://sg.iaea.org/ssac-qs/qsSchema.xsd"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="EmployeeDetails">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="FirstName" type="xs:string"/>
                <xs:element name="MiddleName">
                    <xs:simpleType>
                        <xs:restriction base="xs:string">
                            <xs:minLength value="1"/>
                        </xs:restriction>
                    </xs:simpleType>
                </xs:element>
                <xs:element name="LastName" type="xs:string" />
                <xs:element name="EmailId" type="xs:string" />
                <xs:element name="Mobile" type="xs:integer" minOccurs="1" maxOccurs="1"/>
                <xs:element name="Years">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="Year" type="sg:Year" minOccurs="1" maxOccurs="unbounded"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                <xs:element name="Address">
                    <xs:simpleType>
                        <xs:restriction base="xs:string">
                            <xs:minLength value="5"/>
                            <xs:maxLength value="100"/>
                        </xs:restriction>
                    </xs:simpleType>
                </xs:element>
                <xs:element name="Cars" type="sg:Cars"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="Cars">
        <xs:sequence>
            <xs:element name="Car" type="sg:Car" maxOccurs="unbounded">
            </xs:element>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="Car">
        <xs:simpleContent>
            <xs:extension base="sg:CarModel">
                <xs:attribute name="id" type="xs:string" use="required"/>
                <xs:attribute name="year" type="sg:Year" use="required"/>
                <xs:attribute name="condition" type="xs:string" use="optional"  />
                <xs:attribute name="message" type="xs:string" use="optional" fixed="Driver must be 100 yrs old."/>
            </xs:extension>
        </xs:simpleContent>
    </xs:complexType>
    <xs:simpleType name="CarModel">
        <xs:restriction base="xs:string">
            <xs:enumeration value="Audi"/>
            <xs:enumeration value="Golf"/>
            <xs:enumeration value="BMW"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="Year">
        <xs:restriction base="xs:int">
            <xs:minInclusive value="1900" />
            <xs:maxInclusive value="2200" />
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

内容的提问来源于stack exchange,提问作者Raviraj Bhalerao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 10:37:04