简体   繁体   中英

Default xml attribute value when using LINQ

Let's say you have an XML file:

<experiment
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="experiment.xsd">
  <something />
<experiment>

And you have the xsd file:

...
<xs:attribute name="hello" type="xs:boolean" use="optional" default="false" />
...

Let's assume that the attribute "hello" is an optional attribute of the "something" element with a default value set to "false".

When using XDocument of XML LINQ, the attribute is missing, causing the program to fail while trying to read it:

XDocument xml = XDocument.Load("file.xml");
bool b = bool.Parse(xml.Descendants("something").First().Attribute("hello").Value); // FAIL

Does LINQ load the XML schema automatically (from the "xsi:noNamespaceSchemaLocation" attribute of the root element "experiment") or do I have to force it manually?

How to force LINQ to read the optional attributes and their default values?

The Load method takes an XmlReader, if you use one with the right XmlReaderSettings http://msdn.microsoft.com/en-us/library/1xe0740a (ie requiring validation with ValidationType set to schema and paying attention to schemaLocation respectively noNamespaceSchemaLocation with the proper ValidationFlags) then I think the attribute will be created and populated with the default from the schema.

Here is a short sample:

    XDocument doc;

    XmlReaderSettings xrs = new XmlReaderSettings();
    xrs.ValidationType = ValidationType.Schema;
    xrs.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;


    using (XmlReader xr = XmlReader.Create("../../XMLFile1.xml", xrs))
    {
        doc = XDocument.Load(xr);
    }
    foreach (XElement foo in doc.Root.Elements("foo"))
    {
        Console.WriteLine("bar: {0}", (bool)foo.Attribute("bar"));
    }

With samples file having the contents

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="XMLSchema1.xsd">
  <foo/>
  <foo bar="true"/>
  <foo bar="false"/>
</root>

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="root">
    <xs:complexType>
      <xs:sequence maxOccurs="unbounded">
        <xs:element name="foo">
          <xs:complexType>
            <xs:attribute name="bar" use="optional" type="xs:boolean" default="false"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

the output is

bar: False
bar: True
bar: False

Using this Xml Library XElementExtensions.cs class you can use the Get() method that takes a default value:

XDocument xml = XDocument.Load("file.xml");
bool b = xml.Descendants("something").First().Get("hello", false); 

false is the default you provide.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM