private void VisitNode(XmlElement elem, ItemReference masterRef)
    {
      var textChildren = elem.ChildNodes.OfType<XmlText>().ToList();

      // Add a dependency to the relevant itemTypes
      if (elem.LocalName == "Item" && elem.HasAttribute("type"))
      {
        ItemType itemType;
        if (_metadata.ItemTypeByName(elem.Attribute("type").ToLowerInvariant(), out itemType))
        {
          AddDependency(itemType.Reference, elem, elem, masterRef);
        }
        else
        {
          AddDependency(new ItemReference("ItemType", ItemTypeByNameWhere + elem.Attributes["type"].Value + "'")
          {
            KeyedName = elem.Attributes["type"].Value
          }, elem, elem, masterRef);
        }
      }

      // Item property node
      if (elem.HasAttribute("type") && textChildren.Count == 1 && !string.IsNullOrEmpty(textChildren[0].Value))
      {
        AddDependency(ItemReference.FromItemProp(elem), elem.Parent(), elem, masterRef);
      }
      else if (elem.LocalName == "sqlserver_body" && elem.Parent().LocalName == "Item" && elem.Parent().Attribute("type") == "SQL")
      {
        var names = GetInnovatorNames(elem.InnerText)
          .Select(n => n.FullName.StartsWith("innovator.", StringComparison.OrdinalIgnoreCase) ?
                       n.FullName.Substring(10).ToLowerInvariant() :
                       n.FullName.ToLowerInvariant())
          .Distinct();

        ItemType itemType;
        ItemReference sql;
        foreach (var name in names)
        {
          if (_metadata.ItemTypeByName(name.Replace('_', ' '), out itemType))
          {
            AddDependency(itemType.Reference, elem.Parent(), elem, masterRef);
          }
          else if (_metadata.SqlRefByName(name, out sql))
          {
            AddDependency(sql, elem.Parent(), elem, masterRef);
          }
        }
      }
      else if (elem.LocalName == "data_source" && textChildren.Count == 1 && !string.IsNullOrEmpty(textChildren[0].Value))
      {
        // Property data source dependencies
        var parent = elem.ParentNode as XmlElement;
        if (parent != null && parent.LocalName == "Item" && parent.Attribute("type") == "Property")
        {
          var keyedName = elem.Attribute("keyed_name");
          var itemtype = _metadata.ItemTypes.FirstOrDefault(i => i.Reference.Unique == elem.Parent().Parent().Parent().Attribute("id") && i.IsPolymorphic);
          if (itemtype == null)
          {
            var dataType = parent.Element("data_type");
            if (dataType != null)
            {
              switch (dataType.InnerText.ToLowerInvariant())
              {
                case "list":
                case "mv_list":
                case "filter list":
                  AddDependency(new ItemReference("List", textChildren[0].Value) { KeyedName = keyedName }, parent, elem, masterRef);
                  break;
                case "item":
                  AddDependency(new ItemReference("ItemType", textChildren[0].Value) { KeyedName = keyedName }, parent, elem, masterRef);
                  break;
                case "sequence":
                  AddDependency(new ItemReference("Sequence", textChildren[0].Value) { KeyedName = keyedName }, parent, elem, masterRef);
                  break;
              }
            }
          }
        }
      }
      else if (elem != _elem && elem.LocalName == "Item" && elem.HasAttribute("type")
        && elem.Attribute("action", "") == "get"
        && (elem.HasAttribute("id") || elem.HasAttribute("where")))
      {
        // Item queries
        AddDependency(ItemReference.FromFullItem(elem, true), elem.Parent().Parent(), elem.Parent(), masterRef);
      }
      else if (textChildren.Count == 1 && textChildren[0].Value.StartsWith("vault:///?fileId=", StringComparison.OrdinalIgnoreCase))
      {
        // Vault Id references for image properties
        AddDependency(new ItemReference("File", textChildren[0].Value.Substring(17)), elem.Parent(), elem, masterRef);
      }
      else
      {
        if (elem != _elem && elem.LocalName == "Item" && elem.HasAttribute("type") && elem.HasAttribute("id"))
        {
          _definitions.Add(ItemReference.FromFullItem(elem, elem.Attribute("type") == "ItemType"));
        }
        var isItem = (elem.LocalName == "Item" && elem.HasAttribute("type"));
        ItemProperty newProp;
        ItemReference propRef;

        foreach (var child in elem.Elements())
        {
          if (isItem)
          {
            newProp = new ItemProperty()
            {
              ItemType = elem.Attributes["type"].Value,
              ItemTypeId = (elem.HasAttribute("typeid") ? elem.Attributes["typeid"].Value : null),
              Property = child.LocalName
            };
            if (_metadata.CustomPropertyByPath(newProp, out propRef))
            {
              propRef = propRef.Clone();
              AddDependency(propRef, elem, child, masterRef);
            }
          }
          VisitNode(child, masterRef);
        }
      }
    }
        public void ProcessImport(IDataExtractor extractor, string xslt, int batchSize)
        {
            _extractor = extractor;
              Exception error = null;
              _completeDate = DateTime.MinValue;
              _globallyProcessed = 0;

              try
              {
            extractor.Reset();
            using (_cts = new CancellationTokenSource())
            {
              var opts = new ParallelOptions();
              opts.CancellationToken = _cts.Token;

              Parallel.ForEach(GetXml(extractor, batchSize), opts, xml =>
              {
            int locallyProcessed = 0;
            var doc = new XmlDocument();
            doc.LoadXml(ArasXsltExtensions.Transform(xslt, xml, _conn.ExternalConnection));
            IList<XmlElement> levelElements = new XmlElement[] { doc.DocumentElement };

            while (!levelElements.Any(e => e.LocalName == "AML" || e.LocalName == "SQL"
              || e.LocalName == "sql" || e.LocalName == "Item"))
              levelElements = levelElements.Elements(e => true).ToList();

            var isError = false;
            for (var i = 0; i < levelElements.Count; i++)
            {
              Action<int, int> progressReporter = (curr, count) =>
              {
                var progress = (int)(((double)(count * i + curr) / (count * levelElements.Count)) * batchSize);
                if (progress > locallyProcessed) Interlocked.Add(ref _globallyProcessed, progress - locallyProcessed);
                locallyProcessed = progress;
                SignalProgress(batchSize);
              };

              XmlNode result;
              switch (levelElements[i].LocalName)
              {
                case "AML":
                  result = _conn.CallAction("ApplyAML", levelElements[i], progressReporter);
                  break;
                case "SQL":
                case "sql":
                  result = _conn.CallAction("ApplySQL", levelElements[i], progressReporter);
                  break;
                case "Item":
                  result = _conn.CallAction("ApplyItem", levelElements[i], progressReporter);
                  break;
                default:
                  result = null;
                  break;
              }

              if (_conn.GetError(result) != null)
              {
                _errors.Add(new ErrorEntry() { Error = result.OuterXml, Query = xml });
                isError = true;
                break;
              }
            }

            if (isError) Interlocked.Increment(ref _errorBlocks);
            Interlocked.Add(ref _globallyProcessed, batchSize - locallyProcessed);

            SignalProgress(batchSize);
            opts.CancellationToken.ThrowIfCancellationRequested();
              });
            }
              }
              catch (OperationCanceledException) { }
              catch (Exception ex)
              {
            error = ex;
              }
              finally
              {
            _cts = null;
              }

              _completeDate = DateTime.Now;
              OnActionComplete(new ActionCompleteEventArgs() { Exception = error });
        }
 /// <summary>
 /// Remove keyed_name attributes to make diffing easier
 /// </summary>
 private void RemoveKeyedNameAttributes(XmlElement node)
 {
   if (node.HasAttribute("keyed_name"))
     node.RemoveAttribute("keyed_name");
   foreach (var elem in node.Elements())
     RemoveKeyedNameAttributes(elem);
 }