help with reading xml file

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • davis

    help with reading xml file

    Hello, I am working in .Net C# and have an xml file similar to the one
    below. I have tried using a DataSet but get the error "The same table
    (Gid) cannot be the child table in two nested relations". The file
    has a number of parent nodes at the "<ShipmentHeade r>" level, each of
    which have a number of child nodes. I will not know ahead of time
    which of these parent/child nodes will occur. I have also looked at
    the XmlTextReader, but it looks like I would have to evaluate
    NodeTypes, ReadInnerXml, etc. Is there an easier way?

    <?xml version="1.0" encoding="UTF-8" ?>
    <Shipment>
    <ShipmentHeader >
    <ShipmentGid>
    <Gid>
    <DomainName>xxx xx</DomainName>
    <Xid>xxxxxxx</Xid>
    </Gid>
    </ShipmentGid>
    <ShipmentRefnum >
    <ShipmentRefnum QualifierGid>
    <Gid>
    <Xid>xxxxx</Xid>
    </Gid>
    </ShipmentRefnumQ ualifierGid>
    <ShipmentRefnum Value>xxxxx</ShipmentRefnumV alue>
    <ShipmentRefnum >xxxxx</ShipmentRefnum>
    <ShipmentRefnum QualifierGid>
    <Gid>
    <Xid>xxxx</Xid>
    </Gid>
    </ShipmentRefnumQ ualifierGid>
    <ShipmentRefnum Value>xxxxxx</ShipmentRefnumV alue>
    </ShipmentRefnum>
    </ShipmentHeader>
    </Shipment>
  • Dino Chiesa [Microsoft]

    #2
    Re: help with reading xml file

    > Is there an easier way?
    Yes, using XML Serialization. Here's what I would do.

    Take your sample XML document, and remove the duplicate element names (Gid
    and ShipmentRefnum) . Run that through xsd.exe to infer a schema for the
    document. This generates an XSD. Now modify the XSD to restore the
    original element names. Run the modified XSD through xsd.exe and generate
    classes (xsd.exe /c blah.xsd ).

    This gives you a starting point.

    Build a test driver that
    a. De-serializes from the original XML. Does it work?
    b. instantiates a new "Shipment" object, and serializes that. Does it
    look like your original XML ?

    By testing various XML input documents, tweaking the XSD, regenerating the
    classes, and so, you can iterate, and you can usually get XML Serialization
    to do what you want. For example, xsd.exe often infers a string data type,
    when what you want is an int. Or it may infer the wrong minOccurs and
    maxOccurs limits. So you can make the appropriate mods in the XSD, then
    re-generate, and re-test.

    Your situation is a bit special, because you have elements that are
    repeated, intermixed. For example, ShipmentRefnum has multiple
    ShipmentRefnumQ ualifierGid child elements, and multiple ShipmentRefnumV alue
    child elements, but they are intermixed:
    <ShipmentRefnum >
    <ShipmentRefnum QualifierGid... ./>
    <ShipmentRefnum Value..../>
    <ShipmentRefnum .../>
    <ShipmentRefnum QualifierGid.../>
    <ShipmentRefnum Value..../>

    By default, xsd.exe will infer a schema that employs strongly-typed arrays
    for elements that are repeated . So in your case, it looks like this:

    public class ShipmentRefNum {
    [XmlElement]
    public string ShipmentRefnum;

    [XmlArray]
    [XmlArrayItem("S hipmentRefnumQu alifierGid", typeof(GidWrapp er))]
    public GidWrapper[] ShipmentRefnumQ ualifierGid;

    [XmlElement("Shi pmentRefnumValu e")]
    public string[] ShipmentRefnumV alue;
    }


    When you serialize an instance of this, you will get the array elements in
    order, eg
    <ShipmentRefnum >
    <ShipmentRefnum .../>
    <ShipmentRefnum QualifierGid... ./>
    <ShipmentRefnum QualifierGid.../>
    <ShipmentRefnum Value..../>
    <ShipmentRefnum Value..../>

    which is probably not what you want. Also, I am not sure if
    de-serialization from the sample you posted will work properly, either.

    To address this, you can modify the generated type for ShipmentRefnum to
    contain a single member, an ArrayList. Think of it as a container that can
    hold any combination of elements in any order. Then you attribute that
    arraylist with XmlElement attributes for each of the types (string, int,
    ShipmentRefnumQ ualifierGid) it will contain. like this:

    public class RefnumType {

    [XmlElement(Elem entName="Shipme ntRefnumQualifi erGid",Type=typ eof(GidWrapper)
    )]
    [XmlElement(Elem entName="Shipme ntRefnumValue", Type=typeof(str ing))]
    [XmlElement(Elem entName="Shipme ntRefnum",Type= typeof(int))]
    public ArrayList Items;
    }

    In XSD, this corresponds to a choice element:
    <xs:complexTy pe name="RefnumTyp e">
    <xs:sequence>
    <xs:choice minOccurs="0" maxOccurs="unbo unded">
    <xs:element minOccurs="1" maxOccurs="1" name="ShipmentR efnum"
    type="xs:int" />
    <xs:element minOccurs="0" maxOccurs="1"
    name="ShipmentR efnumQualifierG id" type="GidWrappe r" />
    <xs:element minOccurs="0" maxOccurs="1" name="ShipmentR efnumValue"
    type="xs:string " />
    </xs:choice>
    </xs:sequence>
    </xs:complexType>


    With this structure, you can de-serialize and serialize the XML you posted.
    You can also de-serialize and serialize XML that has these elements in
    different orders, which may or may not be what you want.

    Anyway here's a working example


    This works with the single XML file you sent; it may not work with all. For
    example, you might need to apply the same pattern (using ArrayList) at the
    ShipmentHeader level.

    NB: This will work only if you have at most ONE element type of each data
    type in the arraylist. In other words, you are using the type of the
    arraylist item to determine the element name to spit out in XML. If you
    have 2 element types that are both strings or both ints, then the XML
    Serializer cannot know which element name to emit for that arraylist item of
    that type.


    -Dino


    "davis" <mycsharpmail@y ahoo.com> wrote in message
    news:a8887c5d.0 407290516.7a6bf 7ce@posting.goo gle.com...[color=blue]
    > Hello, I am working in .Net C# and have an xml file similar to the one
    > below. I have tried using a DataSet but get the error "The same table
    > (Gid) cannot be the child table in two nested relations". The file
    > has a number of parent nodes at the "<ShipmentHeade r>" level, each of
    > which have a number of child nodes. I will not know ahead of time
    > which of these parent/child nodes will occur. I have also looked at
    > the XmlTextReader, but it looks like I would have to evaluate
    > NodeTypes, ReadInnerXml, etc. Is there an easier way?
    >
    > <?xml version="1.0" encoding="UTF-8" ?>
    > <Shipment>
    > <ShipmentHeader >
    > <ShipmentGid>
    > <Gid>
    > <DomainName>xxx xx</DomainName>
    > <Xid>xxxxxxx</Xid>
    > </Gid>
    > </ShipmentGid>
    > <ShipmentRefnum >
    > <ShipmentRefnum QualifierGid>
    > <Gid>
    > <Xid>xxxxx</Xid>
    > </Gid>
    > </ShipmentRefnumQ ualifierGid>
    > <ShipmentRefnum Value>xxxxx</ShipmentRefnumV alue>
    > <ShipmentRefnum >xxxxx</ShipmentRefnum>
    > <ShipmentRefnum QualifierGid>
    > <Gid>
    > <Xid>xxxx</Xid>
    > </Gid>
    > </ShipmentRefnumQ ualifierGid>
    > <ShipmentRefnum Value>xxxxxx</ShipmentRefnumV alue>
    > </ShipmentRefnum>
    > </ShipmentHeader>
    > </Shipment>[/color]


    Comment

    Working...