Timy Ash
Timy Ash

Reputation: 107

how to avoid duplicates of attributes in xml c#?

A part of my XML looks like this:

<IOConfig>
  <Packet Name="PacketOut" RemoteAddress="10.0.2.223" RemotePort="2020" NetworkInterface="ETH0">
    <Signal Type="float" Name="x_out" Unit="m/s" Routing="" UnityObject="CraneBoom" UnityName="Out" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="y_out" Unit="m/s" Routing="" UnityObject="CraneBoom" UnityName="Out" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="z_out" Unit="m/s" Routing="" UnityObject="CraneBoom" UnityName="Out" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="alpha_out" Unit="m/s" Routing="" UnityObject="CraneBoom" UnityName="Out" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="theta_out" Unit="m/s" Routing="" UnityObject="CraneBoom" UnityName="Out" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="phi_out" Unit="m/s" Routing="" UnityObject="CraneBoom" UnityName="Out" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="x_out1" Unit="m/s" Routing="" UnityObject="CraneSlewing" UnityName="Out1" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="y_out1" Unit="m/s" Routing="" UnityObject="CraneSlewing" UnityName="Out1" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="z_out1" Unit="m/s" Routing="" UnityObject="CraneSlewing" UnityName="Out1" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="alpha_out1" Unit="m/s" Routing="" UnityObject="CraneSlewing" UnityName="Out1" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="theta_out1" Unit="m/s" Routing="" UnityObject="CraneSlewing" UnityName="Out1" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="phi_out1" Unit="m/s" Routing="" UnityObject="CraneSlewing" UnityName="Out1" NetworkConvert="1"></Signal>
  </Packet>
  <Packet Name="PacketIn" LocalPort="2021" NetworkInterface="ETH0">
    <Signal Type="float" Name="x_in" Unit="m/s" Routing="" UnityObject="CraneBoomCrash" UnityName="collider1" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="y_in" Unit="m/s" Routing="" UnityObject="CraneBoomCrash" UnityName="collider1" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="z_in" Unit="m/s" Routing="" UnityObject="CraneBoomCrash" UnityName="collider1" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="alpha_in" Unit="m/s" Routing="" UnityObject="CraneBoomCrash" UnityName="collider1" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="theta_in" Unit="m/s" Routing="" UnityObject="CraneBoomCrash" UnityName="collider1" NetworkConvert="1"></Signal>
    <Signal Type="float" Name="phi_in" Unit="m/s" Routing="" UnityObject="CraneBoomCrash" UnityName="collider1" NetworkConvert="1"></Signal>
  </Packet>
</IOConfig>

The desired output is: Out, Out1, collider1.

That is, duplicate values of UnityName should not be printed. Can this be done?

Code snipped that reading duplicate values of UnityName:

public class XMLStringReader : MonoBehaviour
{
    public string slectedItem;
    private bool editing = false;

    public string signalsa;
    public XmlReaderSettings settings;

    void OnGUI ()
    {
        if ( GUILayout.Button(slectedItem))
        {
            editing = true;
        }

        XmlReaderSettings settings = new XmlReaderSettings();
        settings.IgnoreWhitespace = true;
        settings.IgnoreComments = true;

        using ( XmlReader reader = XmlReader.Create("D://Docs/Unity3D/cdp/UDPApplication/Components/UDPIOServer.xml", settings) ) 
        {
            while ( reader.Read() ) 
            {
                if ( reader.NodeType == XmlNodeType.Element ) 
                {
                    if ( reader.HasAttributes ) 
                    {
                        if ( reader.GetAttribute("UnityName") != null ) 
                        {
                            signalsa = reader.GetAttribute("UnityName");
                            string [] signalsCDP = {signalsa};

                            if (editing)
                            {
                                for(int i =0; i < signalsCDP.Length; i++) 
                                {
                                    if (GUILayout.Button(signalsCDP[i]))
                                    {
                                        slectedItem = signalsCDP[i];
                                        editing = false;
                                        print(signalsCDP[i].ToString());
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Upvotes: 2

Views: 2047

Answers (4)

horgh
horgh

Reputation: 18534

Just create a collection containing distinct values. Then check whether the next attribute value is already in that collection. If not, add it to the collection and do whatever you need.

List<string> values = new List<string>();

using (XmlReader reader = XmlReader.Create("your path", settings)) 
{
    while (reader.Read()) 
    {
        if (reader.NodeType == XmlNodeType.Element) 
        {
            if (reader.HasAttributes) 
            {
                if (reader.GetAttribute("UnityName") != null) 
                {
                    signalsa = reader.GetAttribute("UnityName");
                    if (!values.Contains(signalsa))
                    {
                        values.Add(signalsa);
                        //rest of your code goes here...
                    }
                }
            }
        }
    }
}

Upvotes: 0

Furqan Safdar
Furqan Safdar

Reputation: 16698

Another way is to define the XML Schema for whatever XML you need apart from Programmatic approach. XML Schema ensures the compliance of the XML.

An XML Schema describes the structure of an XML document.

Have a look at the following references:

  1. XML Schema Tutorial
  2. XSD Attributes

Upvotes: 0

horgh
horgh

Reputation: 18534

You could use LINQ to XML for your task:

XElement x = XElement.Load("File containing your xml");
var list = x.Descendants("Signal")
            .Where(d => d.HasAttributes && d.Attribute("UnityName") != null)
            .Select(d => d.Attribute("UnityName").Value)
            .Distinct();
foreach (string s in list)
    Console.WriteLine(s);

Upvotes: 3

Mx.
Mx.

Reputation: 3665

Iterate over all values and add them with a contains check to a List/Dictionary/Array/Whatever. After that print the collected values.

Here´s the solution:

    internal static void PrintAttributeValues(XDocument scr)
    {
        List<string> values = new List<string>();
        foreach (XElement elem in scr.Descendants("Signal"))
        {
            if (!values.Contains(elem.Attribute("UnityName").Value))
            {
                values.Add(elem.Attribute("UnityName").Value);
            }
        }

        for (int j = 0; j < values.Count; j++)
        {
            Console.WriteLine(values[j]);
        }
    }

Upvotes: 1

Related Questions