如何为此 Linq to XML 函数编写 Lambda 语句?

发布于 2024-09-28 20:58:55 字数 2885 浏览 5 评论 0原文

我正在使用 此 XSD 文件。 与以下内容相关的 XML 部分这个问题在这里:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="https://wsmrc2vger.wsmr.army.mil/rcc/manuals/106-11" 
           targetNamespace="https://wsmrc2vger.wsmr.army.mil/rcc/manuals/106-11"
           elementFormDefault="qualified" 
           attributeFormDefault="unqualified">
    <xs:element name="Tmats">
        <xs:complexType>
            <xs:sequence>
                <xs:annotation>
                    <xs:documentation>TMATS G Group</xs:documentation>
                </xs:annotation>
                <xs:element name="ProgramName" type="xs:string" minOccurs="0">
                    <xs:annotation>
                        <xs:documentation>PN</xs:documentation>
                    </xs:annotation>
                </xs:element>

要获取给定 xs:elementdocumentation 值,我有这个小函数,它递归地遍历后代节点,直到找到 Documentation 元素:

public string GetCode(XElement e)
{
    foreach (var s in e.Elements())
    {
        // If we hit an intervening element, bail out.
        if (s.Name.ToString().Contains("element"))
            return "";

        if (s.Name.ToString().Contains("annotation"))
        {
            // I'll explain this loop in a moment.
            foreach (var t in s.Elements())
            {
                if (t.Name.ToString().Contains("documentation"))
                    return t.Value;
            }
        } 
        else
            return GetCode(s);
    }
    return "";
}

到目前为止一切顺利。单元测试如下所示:

[TestMethod()]
public void GetCodeTest()
{
    string path = @"C:\Documents and Settings\harvey robert\Desktop\Tmats.xsd";

    IEnumerable<XElement> elements =
        from e in XElement.Load(path).Elements()
        select e;

    TmatsDictionary target = new TmatsDictionary(); 
    XElement x = elements.First();
    string actual = target.GetCode(x);
    Assert.AreEqual("TMATS G Group", actual);
}

哪个通过。现在我想通过添加额外的情况来扩展测试,如下所示:

    XElement z = elements.DescendantsAndSelf()
                         .First(y => y.Attribute("name")
                         .ToString().Contains("ProgramName"));

    actual = target.GetCode(z);
    Assert.AreEqual("PN", actual);

...但是由于空对象引用而失败(很可能y.Attribute("name")< /代码>)。

您看到我评论的上面函数中的循环了吗?

// I'll explain this loop in a moment.
foreach (var t in s.Elements())
{
    if (t.Name.ToString().Contains("documentation"))
        return t.Value;
}

之所以这样写,是因为我不知道如何在有效的 Lambda 语句中表达条件。

有什么建议吗?

I am working with this XSD file. The portion of the XML that is relevant to this question is here:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="https://wsmrc2vger.wsmr.army.mil/rcc/manuals/106-11" 
           targetNamespace="https://wsmrc2vger.wsmr.army.mil/rcc/manuals/106-11"
           elementFormDefault="qualified" 
           attributeFormDefault="unqualified">
    <xs:element name="Tmats">
        <xs:complexType>
            <xs:sequence>
                <xs:annotation>
                    <xs:documentation>TMATS G Group</xs:documentation>
                </xs:annotation>
                <xs:element name="ProgramName" type="xs:string" minOccurs="0">
                    <xs:annotation>
                        <xs:documentation>PN</xs:documentation>
                    </xs:annotation>
                </xs:element>

To get the documentation value for a given xs:element, I have this small function, which recursively walks the descendant nodes until it finds the documentation element:

public string GetCode(XElement e)
{
    foreach (var s in e.Elements())
    {
        // If we hit an intervening element, bail out.
        if (s.Name.ToString().Contains("element"))
            return "";

        if (s.Name.ToString().Contains("annotation"))
        {
            // I'll explain this loop in a moment.
            foreach (var t in s.Elements())
            {
                if (t.Name.ToString().Contains("documentation"))
                    return t.Value;
            }
        } 
        else
            return GetCode(s);
    }
    return "";
}

So far so good. The unit test looks like this:

[TestMethod()]
public void GetCodeTest()
{
    string path = @"C:\Documents and Settings\harvey robert\Desktop\Tmats.xsd";

    IEnumerable<XElement> elements =
        from e in XElement.Load(path).Elements()
        select e;

    TmatsDictionary target = new TmatsDictionary(); 
    XElement x = elements.First();
    string actual = target.GetCode(x);
    Assert.AreEqual("TMATS G Group", actual);
}

Which passes. Now I want to extend the test by adding an additional case, like this:

    XElement z = elements.DescendantsAndSelf()
                         .First(y => y.Attribute("name")
                         .ToString().Contains("ProgramName"));

    actual = target.GetCode(z);
    Assert.AreEqual("PN", actual);

...But this fails due to a null object reference (most likely y.Attribute("name")).

Did you see the loop in the function above that I commented?

// I'll explain this loop in a moment.
foreach (var t in s.Elements())
{
    if (t.Name.ToString().Contains("documentation"))
        return t.Value;
}

It's written that way because I can't figure out how to express the condition in a Lambda statement that works.

Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

闻呓 2024-10-05 20:58:55

您需要使用命名空间:

XNamespace ns = "https://wsmrc2vger.wsmr.army.mil/rcc/manuals/106-11";
XElement z = elements.DescendantsAndSelf()
                     .First(y => y.Attribute(ns + "name")
                         .Value.Contains("ProgramName"));

You need to use namespaces:

XNamespace ns = "https://wsmrc2vger.wsmr.army.mil/rcc/manuals/106-11";
XElement z = elements.DescendantsAndSelf()
                     .First(y => y.Attribute(ns + "name")
                         .Value.Contains("ProgramName"));
梦里人 2024-10-05 20:58:55

试试这个

elements.DescendantsAndSelf().
                First(y => y.Attribute(XName.Get("name", "http://www.w3.org/2001/XMLSchema")));

Try this

elements.DescendantsAndSelf().
                First(y => y.Attribute(XName.Get("name", "http://www.w3.org/2001/XMLSchema")));
画▽骨i 2024-10-05 20:58:55

您的问题是 y.Attribute("name").ToString().Contains("ProgramName") 在每个不包含“name”属性的元素上都会失败。您需要这样的东西:

y.Attribute("name") != null &&
y.Attribute("name").ToString().Contains("ProgramName");

如果您希望所有 元素都包含 name 属性,您可以忽略 null 检查并执行以下操作:

XElement z = elements.DescendantsAndSelf(
                         "{http://www.w3.org/2001/XMLSchema}element")
                     .First(y => y.Attribute("name") 
                     .ToString().Contains("ProgramName"));

编辑:请注意,我添加了扩展名称以包含命名空间 URL。看看是否有效。

Your problem is that y.Attribute("name").ToString().Contains("ProgramName") will fail on every element that doesn't contain a "name" attribute. You need something like this:

y.Attribute("name") != null &&
y.Attribute("name").ToString().Contains("ProgramName");

If you expect all <element> elements to contain a name attribute, you can ignore the null check and do this:

XElement z = elements.DescendantsAndSelf(
                         "{http://www.w3.org/2001/XMLSchema}element")
                     .First(y => y.Attribute("name") 
                     .ToString().Contains("ProgramName"));

EDIT: Note that I added the expanded name to include the namespace URL. See if that works.

攒眉千度 2024-10-05 20:58:55

这是有效的代码。

请注意 DescendantsAndSelf() 调用中对 GetName() 方法的调用。这将返回格式正确、以 URI 为前缀的名称,格式为 {http://www.w3.org/2001/XMLSchema}element,它将与 xs:element 正确匹配代码>名称。

结果是,DescendantsAndSelf() 仅返回那些名为 xs:element 的元素,所有这些元素都具有与其关联的属性(因此不可能出现空引用)引用 Attributes 集合时出错)。

[TestMethod()]
public void GetCodeTest()
{
    string path = @"C:\TestArea\Tmats_09-2010.xml";

    IEnumerable<XElement> elements =
        from e in XElement.Load(path).Elements()
        select e;

    TmatsDictionary target = new TmatsDictionary();            
    XNamespace ns = "http://www.w3.org/2001/XMLSchema";

    XElement z = elements.DescendantsAndSelf(ns.GetName("element")) 
                         .First(y => y.Attribute("name")
                         .Value.Equals("ProgramName"));

    actual = target.GetCode(z);
    Assert.AreEqual("PN", actual);
}

Here is the code that works.

Notice the call to the GetName() method in the DescendantsAndSelf() call. This returns a properly formatted URI-prefixed name of the form {http://www.w3.org/2001/XMLSchema}element, which will match correctly to the xs:element names.

The result is that DescendantsAndSelf() returns only those elements having the name xs:element, all of which have attributes associated with them (so there is no chance of a null reference error when referencing the Attributes collection).

[TestMethod()]
public void GetCodeTest()
{
    string path = @"C:\TestArea\Tmats_09-2010.xml";

    IEnumerable<XElement> elements =
        from e in XElement.Load(path).Elements()
        select e;

    TmatsDictionary target = new TmatsDictionary();            
    XNamespace ns = "http://www.w3.org/2001/XMLSchema";

    XElement z = elements.DescendantsAndSelf(ns.GetName("element")) 
                         .First(y => y.Attribute("name")
                         .Value.Equals("ProgramName"));

    actual = target.GetCode(z);
    Assert.AreEqual("PN", actual);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文