【问题标题】:Linq to XML Namespace problemsLinq to XML 命名空间问题
【发布时间】:2011-04-05 23:01:05
【问题描述】:

您好,

我的目标:要验证 XML 文档,然后将数据加载到自定义对象中。我正在使用 Linq to XML。

我的情况:我正在为命名空间和/或 Linq 语法而苦苦挣扎。我以为一切正常。代码读取 XML 并加载对象,但意识到 XDocument.Validate 正在传递所有内容而不是真正进行验证。我猜这是验证不严。为了验证 XDocument.Validate() 方法,我在 XML 文件中添加了一个命名空间。验证有效,但现在我的 Linq 查询创建的 XElement 在尝试访问 .Element("Field").value 时返回 null。

我的问题:

  1. 如何验证 XML 文档并访问元素的值?除了使用 XDocument.Validate 之外,我是否应该使用另一个过程来针对 XSD 验证 XML?
  2. 是我的 Linq 查询有问题吗?
  3. 当我尝试在 Linq 查询中指定特定元素时,我永远不会得到结果。它 仅在以下情况下有效

    IEnumerable<XElement> residents =
            from xeRes in xD.Elements()
            select xeRes;
    

    但是

    IEnumerable<XElement> residents =
            from xeRes in xD.Elements("Resident")
            select xeRes;
    

什么都不返回。

欢迎提出任何建议。

谢谢,

代码片段:

XSD

<?xml version="1.0" encoding="utf-8"?>  <xsd:schema xmlns="http://kinduit.net/ResidentNS" xmlns:schema="http://kinduit.net/ResidentNS" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified"><xsd:import namespace="http://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="http://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd" />
<xsd:element name="Resident">
    <xsd:complexType>
        <xsd:sequence>
            <xsd:element name="FacilityID">
                <xsd:simpleType>
                    <xsd:restriction base="sqltypes:varchar" sqltypes:localeId="1033" sqltypes:sqlCompareOptions="IgnoreCase IgnoreKanaType IgnoreWidth" sqltypes:sqlSortId="52">
                        <xsd:maxLength value="50" />
                    </xsd:restriction>
                </xsd:simpleType>
            </xsd:element>
            <xsd:element name="ResidentID"  maxOccurs="unbounded">
                <xsd:simpleType>
                    <xsd:restriction base="sqltypes:varchar" sqltypes:localeId="1033" sqltypes:sqlCompareOptions="IgnoreCase IgnoreKanaType IgnoreWidth" sqltypes:sqlSortId="52">
                        <xsd:maxLength value="20" />
                    </xsd:restriction>
                </xsd:simpleType>
            </xsd:element>
            <xsd:element name="ResidentID2"  maxOccurs="unbounded">
                <xsd:simpleType>
                    <xsd:restriction base="sqltypes:varchar" sqltypes:localeId="1033" sqltypes:sqlCompareOptions="IgnoreCase IgnoreKanaType IgnoreWidth" sqltypes:sqlSortId="52">
                        <xsd:maxLength value="20" />
                    </xsd:restriction>
                </xsd:simpleType>
            </xsd:element>...

XML

<?xml version="1.0"?><Resident xmlns="http://kinduit.net/ResidentNS">
<FacilityID>WARMSPRINGS</FacilityID>
<ResidentID>WS585459</ResidentID>
<ResidentID2>145214</ResidentID2>...

C#

        // Validate XML Schema...
        XmlSchemaSet sc = new XmlSchemaSet();
        XNamespace xNs = "http://kinduit.net/ResidentNS";

        try
        {
            // Validate against the XSD...
            string location = System.Reflection.Assembly.GetAssembly(typeof(ElementsBC.Interface)).Location;
            sc.Add(xNs.ToString(), location.Replace("ElementsBC.dll", "") + "\\InterfaceXSD\\resident.xsd");
            XDocument xD = this.ConvertToXDocument(ResidentXML);
            xD.Validate(sc, (sender, e) => { throw new Exception(e.Message); }, true);

            IEnumerable<XElement> residents =
                from xeRes in xD.Elements()
                select xeRes;

            counts[0] = residents.Count();

            foreach (XElement el in residents)
            {
                try
                {
                    // get facility...
                    string facilityid = el.Element("FacilityID").Value.ToString();

如果 XML 中存在命名空间,则最后一行返回 null。如果没有 Namespace,则此代码运行 lax Validation,但可以读取该值。

建议?

【问题讨论】:

    标签: xml linq linq-to-xml


    【解决方案1】:

    您需要在调用中包含命名空间。

    XNamespace ns = xD.GetDefaultNamespace() // Or some other way of getting the namespace you want.
    IEnumerable<XElement> residents = from xeRes in xD.Elements(ns + "Resident")        
                                      select xeRes;
    

    【讨论】:

    • 谢谢蒂姆。我试试看。
    • Tim,除了需要像你说的那样在调用中包含命名空间外,我还缺少 XSD 中的目标命名空间。我还必须在调用 .Element 时添加命名空间。感谢您的帮助。
    【解决方案2】:

    感谢 Tim Jarvis 和 Broken Glass。我通过结合他们的回答找到了答案。上面的代码有三个问题。

    1. 我在 XSD 中缺少 targetNamespace。
    2. 我需要在我的 Linq 查询中添加命名空间,正如 Tim Jarvis 和 Broken Glass 所指出的那样。
    3. 我需要在 XElement.Element 的 XName 参数中添加命名空间。

    请参阅下面的更正代码。

    XSD

    <?xml version="1.0" encoding="utf-8"?><xsd:schema xmlns:xs="http://kinduit.net/ResidentNS" targetNamespace="http://kinduit.net/ResidentNS" xmlns="http://kinduit.net/ResidentNS" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">
    <xsd:import namespace="http://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="http://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd" />
    <xsd:element name="Resident">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="FacilityID">
                    <xsd:simpleType>
                        <xsd:restriction base="sqltypes:varchar" sqltypes:localeId="1033" sqltypes:sqlCompareOptions="IgnoreCase IgnoreKanaType IgnoreWidth" sqltypes:sqlSortId="52">
                            <xsd:maxLength value="50" />
                        </xsd:restriction>
                    </xsd:simpleType>
                </xsd:element>
                <xsd:element name="ResidentID"  maxOccurs="unbounded">
                    <xsd:simpleType>
                        <xsd:restriction base="sqltypes:varchar" sqltypes:localeId="1033" sqltypes:sqlCompareOptions="IgnoreCase IgnoreKanaType IgnoreWidth" sqltypes:sqlSortId="52">
                            <xsd:maxLength value="20" />
                        </xsd:restriction>
                    </xsd:simpleType>
                </xsd:element>
                <xsd:element name="ResidentID2"  maxOccurs="unbounded">
                    <xsd:simpleType>
                        <xsd:restriction base="sqltypes:varchar" sqltypes:localeId="1033" sqltypes:sqlCompareOptions="IgnoreCase IgnoreKanaType IgnoreWidth" sqltypes:sqlSortId="52">
                            <xsd:maxLength value="20" />
                        </xsd:restriction>
                    </xsd:simpleType>
                </xsd:element>...
    

    XML:没有变化

    C#

     // Validate XML Schema...
            XmlSchemaSet sc = new XmlSchemaSet();
            XNamespace xNs = "http://kinduit.net/ResidentNS";
    
            try
            {
                // Validate against the XSD...
                string location = System.Reflection.Assembly.GetAssembly(typeof(ElementsBC.Interface)).Location;
                sc.Add(xNs.ToString(), location.Replace("ElementsBC.dll", "") + "\\InterfaceXSD\\resident.xsd");
                XDocument xD = this.ConvertToXDocument(ResidentXML);
                xD.Validate(sc, (sender, e) => { throw new Exception(e.Message); }, true);
    
                IEnumerable<XElement> residents = 
                    from xeRes in xD.Elements(xNs + "Resident")
                    select xeRes;
    
                counts[0] = residents.Count();
    
                foreach (XElement el in residents)
                {
                    try
                    {
                        // get facility...
                        string facilityid = el.Element(xNs + "FacilityID").Value.ToString();
    

    谢谢!

    【讨论】:

      【解决方案3】:

      你必须声明和使用命名空间:

      XNamespace xsd = "http://www.w3.org/2001/XMLSchema";
      

      此外,您的 XML 中没有 Resident 元素 - 有一个名为 element 的元素具有以“驻留”开头的属性 name。这些元素不是根节点的直接子节点,因此您必须在查询中使用 Descendands() 而不是 Elements()。

      话虽如此,这对我有用(返回 3 个节点):

      XDocument xD = XDocument.Load("test.xml");
      XNamespace xsd = "http://www.w3.org/2001/XMLSchema";
      
      IEnumerable<XElement> residents = from xeRes in xD.Descendants(xsd + "element")
                                        where xeRes.Attribute("name") != null 
                                        && xeRes.Attribute("name").Value.StartsWith("Resident") 
                                        select xeRes;
      

      【讨论】:

      • 应该用我的 XML 文件中的值替换“元素”和“名称”吗?如果使用我的 XSD/XML,Linq 会是什么样子?感谢您的帮助。
      • "element" 和 "name" 取自示例中给出的 XML 文件,请参阅 XML 中的 &lt;xsd:element/&gt;
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-04-06
      • 1970-01-01
      • 2012-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多