0

Let's consider that this was automatically generated xml file and in the second Address tag there is nothing. It is null.

If it was not null , we are going to make a list for address and then continue with a class declaration as below. But if we do so, because of a null address tag it gives us an error.

If possible I would like to add an if statement saying that

if it is null , store it as string. if it is not null , go with the list thing.

Could you please show me in code part how to do that?

Best regards

xml sample:

<?xml version="1.0"?>
<XMLCD>
 <Personnel>
  <AddressDirectory>
    <Owner>Jerry</Owner>
    <Age>29</Age>
    <Company>123</Company>
    <Address>
     <ST>
      <HouseNo>1</HouseNo>
      <StreetName>5th</StreetName>
      <Town>Elmsford</Town>
     </ST>
    </Address>
    <Address> 
    </Address>
  </AddressDirectory>
  <AddressDirectory>
      <Owner>Joe</Owner>
      <Age>24</Age>
      <Company>456</Company>
      <Address>
       <ST>
        <HouseNo>1</HouseNo>
        <StreetName>10Blvd</StreetName>
        <Town>StMichael</Town>
       </ST>
      </Address>
      <Address> 
      </Address>
  </AddressDirectory>
 </Personnel>
</XMLCD>

My code:

        OpenFileDialog ofd = new OpenFileDialog();
        opnFileName = ofd.FileName;

        XmlSerializer deserializer = new XmlSerializer(typeof(XMLCD));
        TextReader reader = new StreamReader(this.opnFileName);
        object obj = deserializer.Deserialize(reader);
        XMLCD XmlData = (XMLCD)obj;
        reader.Close();

    public class XMLCD
    {
         [XmlElement("Personnel")]
         public List<Personnel> PersonnelList = new List<Personnel>();

         public class Personnel
         {
           [XmlElement("AddressDirectory")]
           public List<AddressDirectory> AddressDirectoryList = new List<AddressDirectory>();

           public class AddressDirectory
           {
                 [XmlElement("Owner")]
                 public string Owner{ get; set; }

                 [XmlElement("Age")]
                 public string Age{ get; set; }

                 [XmlElement("Company")]
                 public string Company{ get; set; }


                 [XmlElement("Address")]
                 public List<Address> AddressList = new List<Address>();

                 public class Address
                 {
                       [XmlElement("ST")]
                       public List<ST> STList = new List<ST>();

                       public class ST
                       {
                         [XmlElement("HouseNo")]
                         public string HouseNo{ get; set; }

                         [XmlElement("StreetName")]
                         public string StreetName{ get; set; }

                         [XmlElement("Town")]
                         public string Town{ get; set; }
                }
     }
  }
}

The code above works great only for xml codes who have no null adress tags. When the xml code has null adress tags as shown above it gives an error.

ZMC
  • 25
  • 2
  • 5
  • It doesn't look like the right format to me, the Address elements should be children of an Addresses or some collection element. The easiest way is after import just remove all null entries from the list. – Ron Beyer May 02 '15 at 15:02
  • What should be stored as a string if you encounter an empty Address element? – Filburt May 02 '15 at 15:02
  • 1
    Is this xml handcoded or generated by serialization, because you shouldn't try to deserialize handcoded xml object if you can avoid it. That's asking for a whole world of hurt. – Nick Bailey May 02 '15 at 15:09
  • There are only 2 possible solutions: 1) Restrict the Xml schema to not allow empty Address elements by making the child elments required 2) Handle empty address elements in your deserialized object. ... unless you want to implement your own XmlSerializer. – Filburt May 02 '15 at 15:23
  • I have added the actual situation in my post. Unfortunately xml code is serialized from some other program so can't make any changes on it. Address element is already a child of something else. All i need to solve is let the code to see whether it is null or it has some childs with values. – ZMC May 02 '15 at 20:31

1 Answers1

1

If you only control de-serializing, you can simply remove unwanted empty Address entries right after deserialization using the Linq .RemoveAll() extension method:

XmlSerializer deserializer = new XmlSerializer(typeof(XMLCD));
XMLCD XmlData;

using (var reader = new StreamReader(this.opnFileName))
{
    XmlData = deserializer.Deserialize(reader) as XMLCD;
}

// loop over all Personnel to cleanse their AddressDirectoryList.AddressList
foreach (Personnel p in XmlData.PersonnelList)
{
    foreach (AddressDirectory ad in p.AddressDirectoryList)
    {
        // RemoveAll predicate checks if ALL properties are null or empty
        ad.AddressList.RemoveAll(a =>
            (string.IsNullOrEmpty(a.HouseNo) &&
             string.IsNullOrEmpty(a.StreetName) &&
             string.IsNullOrEmpty(a.City))
        );
    }
}

Basically the RemoveAll() method just iterates over all items in the AddressList collection.

To simplify the validation you could extend your Address class to validate itself:

public class Address
{
    [XmlElement("HouseNo")]
    public string HouseNo { get; set; }

    [XmlElement("StreetName")]
    public string StreetName{ get; set; }

    [XmlElement("City")]
    public string City{ get; set; }

    [XmlIgnore]
    public bool IsValid
    {
        get
        {
            return !string.IsNullOrEmpty(this.HouseNo)
                && !string.IsNullOrEmpty(this.StreetName)
                && !string.IsNullOrEmpty(this.City);
        }
    }
}

which will allow to use a single condition in your RemoveAll predicate:

ad.AddressList.RemoveAll(a => !a.IsValid);

An non-Linq alternative could be to transform the source Xml using Xslt to filter out empty Address elements.

Filburt
  • 17,626
  • 12
  • 64
  • 115
  • My code is as below.I deserialize an xml file with more than 4000 tags except the one above with that code What i understand is you are saying do nothing with MyClass, instead in the code part remove the null address tags. If so,am i going to use my 2,3,4 and 5th code line? Thanks for your help. XmlSerializer deserializer = new XmlSerializer(typeof(AddressDirectory)); TextReader reader = new StreamReader(this.opnFileName); object obj = deserializer.Deserialize(reader); MyClass XmlData = (MyClass)obj; reader.Close(); – ZMC May 03 '15 at 16:35
  • See my updated example. The only differences to your approach is 1) the `using` block which automatically releases any resources the StreamReader uses and 2) the direct cast to `AddressDirectory`. – Filburt May 03 '15 at 18:49
  • Thanks for your answer. I'm sorry that i made a mistake. please change MyClass with AdressDirectory. my code is: XmlSerializer deserializer = new XmlSerializer(typeof(AddressDirectory)); TextReader reader = new StreamReader(this.opnFileName); object obj = deserializer.Deserialize(reader); AddressDirectory XmlData = (AddressDirectory)obj; reader.Close(); – ZMC May 04 '15 at 06:45
  • I already factored that into the merged example; `MyClass` was just a variable name there; the type was already `AddressDirectory`. – Filburt May 04 '15 at 07:03
  • Thanks for your answer. I can't use XmlData.AddressList.RemoveAll(a => a.HouseList.Count == 0); There is two more lists departmentlist and personnellist and then address comes. When i try to write i cant get te remove all thing. I used [0] i think i need a for loop to iterate and remove all of them. XmlData.DepartmentList[0].PersonnelList[0].AddressList.RemoveAll(a => a.HouseList.Count == 0); – ZMC May 04 '15 at 08:59
  • Could you add the basic structure with all the lists in your question? I'm not quite sure if I understand how they are nested. – Filburt May 04 '15 at 10:07
  • I modified my answer to fit your actual structure and added a suggestion on how to simply your Address element validation. – Filburt May 05 '15 at 07:56
  • I'm little bit confused. I'm trying to change my real xml file into something everybody can understand. Sorry for that. I have added ST tag (which is list in code) after address tag. I can't do the remove all thing because after address there is a list STList. So which code shall i use in order to remove them? (Your xml deserializer works great. For each sounds pretty cool. But because of the ST list i couldn't use the remove all thing.) Regards – ZMC May 06 '15 at 10:15