October 5, 2005

Pattern/Sample To Parse Xml Using XmlReader

Heres some sample text that shows how to parse some Xml with XmlTextReader I am trying to demonstrate parsing of attributes, empty nodes and layered nodes all in one go that’s why its quite complex

   #region ReadIBVDescriptor Method

  private const string ELEMENT_NAME = "IBVDescriptor";

  // Parse some xml fragment 
  // <IBVDescriptor>...</IBVDescriptor>
  // On exit the XmlReader is pointing to the 
  // node immediately following
  // the end element node ('</IBVDescriptor>')
  public static IBVDescriptor ReadIBVDescriptor(
    XmlReader xmlReader)
  {
    // Move to the next start element
    // ('<IBVDescriptor>') if not already there
    MoveTo(xmlReader, XmlNodeType.Element);
    _Assert((xmlReader.Name == IBVDescriptor_ELEMENT_NAME)
      &&amp; (xmlReader.NodeType == XmlNodeType.Element));
    int startDepth = xmlReader.Depth;
    bool elementIsEmpty = xmlReader.IsEmptyElement;
    // PARSE ATTRIBUTES of the descriptor root node
    string name = xmlReader.GetAttribute("Name");
    string provider = xmlReader.GetAttribute("Provider");
    string tmp = xmlReader.GetAttribute("RunningStatus");
    // To parse an attribute directly into an 'enum' value
    // use the following code pattern
    Service.RunningStatuses runningStatus =
      (Service.RunningStatuses)Enum.Parse(
      typeof(Service.RunningStatuses), tmp);
    byte type = byte.Parse(xmlReader.GetAttribute("Type"));
  
    IBVDescriptor descriptor = new IBVDescriptor(
      name, provider, runningStatus, type);
     if (!elementIsEmpty)
    {
      xmlReader.Read();
       bool endOfDesc = false;
      DataService ds = null;
      string val;
      while (true)
      {
        // look for the end of the main parent element node
        endOfDesc = (xmlReader.Name == ELEMENT_NAME) &&
          (xmlReader.NodeType == XmlNodeType.EndElement);
        if (endOfDesc)
          break;

        // PARSE ELEMENT NODES
        // Begin Element Processing ''
        if (xmlReader.NodeType == XmlNodeType.Element)
        {
          // Do something with the node
          switch (xmlReader.Name)
          {
            case "DataService":
              _Assert(ReferenceEquals(ds, null));
              string id = xmlReader.
                GetAttribute("DataServiceId");
              ds = new DataService(id);
              xmlReader.Read();
              break;

            case "Reserved":
              // Interpret an element node. In this
              // case we assume it cannot be empty
              _Assert(!xmlReader.IsEmptyElement);
              val = xmlReader.ReadElementString();
              ds.Reserved = val;
              break;
            case "FieldParity":
              // Can read in an entire Xml
              // fragment as a string if required
              val = xmlReader.ReadOuterXml();
              descriptor.FieldParity = val;
              break;
            case "Authorisation":
              // Can devolve complex xml fragments to
other routines
              Authorisation val =
XmlHelper.ReadAuthorisation(xmlReader);
                descriptor.Authorisation = val;
                break;
            default: // Whitespace etc.
              //TODO_NODE(xmlReader);
              // Can use Skip() to ignore unhandled XML
              XmlHelper.Skip(xmlReader);
                break ;
          }
        }
        else
        {
          // End Element Processing '</xxx>'
          if (xmlReader.NodeType == XmlNodeType.EndElement)
          {
            if (xmlReader.Name == "DataService")
            {
              _Assert(!ReferenceEquals(ds, null));
              descriptor.AddDataService(ds);
              ds = null;
            }
          }
          xmlReader.Read();
        }
      }
  
      // Use xmlReader.Depth to ensure we are still
      _Assert(xmlReader.Depth == startDepth);
      _Assert((xmlReader.Name == IELEMENT_NAME) &&amp;
        (xmlReader.NodeType == XmlNodeType.EndElement));
      xmlReader.Read();
    }
    return descriptor;
  }

  #endregion ReadIBVDescriptor Method

  // Helper method to skip the next node.
  // 'XmlTextReader.Skip()' does not handle
  // empty element nodes, ie.
  // those of format '<xxx />'
  public static void Skip(XmlReader xmlReader)
  {
    if (xmlReader.IsEmptyElement)
      xmlReader.Read();
    else
      xmlReader.Skip();    
  }

  public static void MoveTo(
          XmlReader xmlReader, XmlNodeType nodeType)
  {
     while (!xmlReader.EOF && 
            (xmlReader.NodeType != nodeType) )
     {
        xmlReader.Read() ;
     }
  }

No comments: