Large XML file, XmlDocument is not executable, but you need to be able to search

I am struggling with a reasonable logical loop to extract nodes from an XML file that is too large to be used with XPath that supports .NET classes.

I am trying to replace a single line of code that I had (called SelectNodes with an XPath query string) with code that does the same but uses XmTextReader.

I need to go down several levels, as shown by the previously used XPath query (which was for reference):

ConfigurationRelease/Profiles/Profile[Name='MyProfileName']/Screens/Screen[Id='MyScreenId']/Settings/Setting[Name='MySettingName']

I thought it would be annoying, but simple. However, I just can't get the loop to the right.

I need to get a node, check the node under this to see if the value matches the target line, and then move on if this happens or skip this branch if it is not specified.

In fact, I think that my problem is that I do not know how to ignore the branch if I do not use it. I cannot let it go with irrelevant branches, because the element names are not unique (as shown in the XPath request).

I thought I could support some booleans, for example. bool expectingProfileName, which gets true when I delete the node profile. However, if this is not a specific node profile, I cannot get out of this branch.

So ... I hope this makes sense to someone ... I have been looking at the problem for a couple of hours and can just skip something obvious .....

I would like to publish part of the file, but I can’t understand what the structure looks like:

ConfigRelease > Profiles > Profile > Name > Screens > Screen > Settings > Setting > Name

I will know the file_name, instance_name, and username, and I need the node setup.

, . , . , XML , , , .

.

. XPathDocument, . Unfortunatley, , , XPathDocument .

, XmlDocument. 4 , , -, , , XmlDocument. , , , , . , DataSet, .

2

, , , . , . , , reset , . . , , , . , , , , , , - , .......

+3
6

, , .

, Xml. , - .

, ( ), .

, ​​ , .

.

+2

XPathDocument.

XPathDocument , XmlDocument, XPath .

+9

, , . , , , , . . , , (. Output()).

:

using System;

using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;

namespace XPathInCE
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                if (args.Length != 2)
                {
                    ShowUsage();
                }
                else
                {
                    Extract(args[0], args[1]);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("{0} was thrown", ex.GetType());
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }

            Console.WriteLine("Press ENTER to exit");
            Console.ReadLine();
        }

        private static void Extract(string filePath, string queryString)
        {
            if (!File.Exists(filePath))
            {
                Console.WriteLine("File not found! Path: {0}", filePath);
                return;
            }

            XmlReaderSettings settings = new XmlReaderSettings { IgnoreComments = true, IgnoreWhitespace = true };
            using (XmlReader reader = XmlReader.Create(filePath, settings))
            {
                XPathQuery query = new XPathQuery(queryString);
                query.Find(reader);
            }
        }

        static void ShowUsage()
        {
            Console.WriteLine("No file specified or incorrect number of parameters");
            Console.WriteLine("Args must be: Filename XPath");
            Console.WriteLine();
            Console.WriteLine("Sample usage:");
            Console.WriteLine("XPathInCE someXmlFile.xml ConfigurationRelease/Profiles/Profile[Name='MyProfileName']/Screens/Screen[Id='MyScreenId']/Settings/Setting[Name='MySettingName']");
        }

        class XPathQuery
        {
            private readonly LinkedList<ElementOfInterest> list = new LinkedList<ElementOfInterest>();
            private LinkedListNode<ElementOfInterest> currentNode;

            internal XPathQuery(string query)
            {
                Parse(query);
                currentNode = list.First;
            }

            internal void Find(XmlReader reader)
            {
                bool skip = false;
                while (true)
                {
                    if (skip)
                    {
                        reader.Skip();
                        skip = false;
                    }
                    else
                    {
                        if (!reader.Read())
                        {
                            break;
                        }
                    }
                    if (reader.NodeType == XmlNodeType.EndElement
                            && String.Compare(reader.Name, currentNode.Previous.Value.ElementName, StringComparison.CurrentCultureIgnoreCase) == 0)
                    {
                        currentNode = currentNode.Previous ?? currentNode;
                        continue;
                    }
                    if (reader.NodeType == XmlNodeType.Element)
                    {
                        string currentElementName = reader.Name;
                        Console.WriteLine("Considering element: {0}", reader.Name);

                        if (String.Compare(reader.Name, currentNode.Value.ElementName, StringComparison.CurrentCultureIgnoreCase) != 0)
                        {
                            // don't want
                            Console.WriteLine("Skipping");
                            skip = true;
                            continue;
                        }
                        if (!FindAttributes(reader))
                        {
                            // don't want
                            Console.WriteLine("Skipping");
                            skip = true;
                            continue;
                        }

                        // is there more?
                        if (currentNode.Next != null)
                        {
                            currentNode = currentNode.Next;
                            continue;
                        }

                        // we're at the end, this is a match! :D
                        Console.WriteLine("XPath match found!");
                        Output(reader, currentElementName);
                    }
                }
            }

            private bool FindAttributes(XmlReader reader)
            {
                foreach (AttributeOfInterest attributeOfInterest in currentNode.Value.Attributes)
                {
                    if (String.Compare(reader.GetAttribute(attributeOfInterest.Name), attributeOfInterest.Value,
                                       StringComparison.CurrentCultureIgnoreCase) != 0)
                    {
                        return false;
                    }
                }
                return true;
            }

            private static void Output(XmlReader reader, string name)
            {
                while (reader.Read())
                {
                    // break condition
                    if (reader.NodeType == XmlNodeType.EndElement
                        && String.Compare(reader.Name, name, StringComparison.CurrentCultureIgnoreCase) == 0)
                    {
                        return;
                    }

                    if (reader.NodeType == XmlNodeType.Element)
                    {
                        Console.WriteLine("Element {0}", reader.Name);
                        Console.WriteLine("Attributes");
                        for (int i = 0; i < reader.AttributeCount; i++)
                        {
                            reader.MoveToAttribute(i);
                            Console.WriteLine("Attribute: {0} Value: {1}", reader.Name, reader.Value);
                        }
                    }

                    if (reader.NodeType == XmlNodeType.Text)
                    {
                        Console.WriteLine("Element value: {0}", reader.Value);
                    }
                }
            }

            private void Parse(string query)
            {
                IList<string> elements = query.Split('/');
                foreach (string element in elements)
                {
                    ElementOfInterest interestingElement = null;
                    string elementName = element;
                    int attributeQueryStartIndex = element.IndexOf('[');
                    if (attributeQueryStartIndex != -1)
                    {
                        int attributeQueryEndIndex = element.IndexOf(']');
                        if (attributeQueryEndIndex == -1)
                        {
                            throw new ArgumentException(String.Format("Argument: {0} has a [ without a corresponding ]", query));
                        }
                        elementName = elementName.Substring(0, attributeQueryStartIndex);
                        string attributeQuery = element.Substring(attributeQueryStartIndex + 1,
                                    (attributeQueryEndIndex - attributeQueryStartIndex) - 2);
                        string[] keyValPair = attributeQuery.Split('=');
                        if (keyValPair.Length != 2)
                        {
                            throw new ArgumentException(String.Format("Argument: {0} has an attribute query that either has too many or insufficient = marks. We currently only support one", query));
                        }
                        interestingElement = new ElementOfInterest(elementName);
                        interestingElement.Add(new AttributeOfInterest(keyValPair[0].Trim().Replace("'", ""),
                            keyValPair[1].Trim().Replace("'", "")));
                    }
                    else
                    {
                        interestingElement = new ElementOfInterest(elementName);
                    }

                    list.AddLast(interestingElement);
                }
            }

            class ElementOfInterest
            {
                private readonly string elementName;
                private readonly List<AttributeOfInterest> attributes = new List<AttributeOfInterest>();

                public ElementOfInterest(string elementName)
                {
                    this.elementName = elementName;
                }

                public string ElementName
                {
                    get { return elementName; }
                }

                public List<AttributeOfInterest> Attributes
                {
                    get { return attributes; }
                }

                public void Add(AttributeOfInterest attribute)
                {
                    Attributes.Add(attribute);
                }
            }

            class AttributeOfInterest
            {
                private readonly string name;
                private readonly string value;

                public AttributeOfInterest(string name, string value)
                {
                    this.name = name;
                    this.value = value;
                }

                public string Value
                {
                    get { return value; }
                }

                public string Name
                {
                    get { return name; }
                }
            }
        }
    }
}

, :

<?xml version="1.0" encoding="utf-8" ?>
<ConfigurationRelease>
  <Profiles>
    <Profile Name ="MyProfileName">
      <Screens>
        <Screen Id="MyScreenId">
          <Settings>
            <Setting Name="MySettingName">
              <Paydirt>Good stuff</Paydirt>
            </Setting>
          </Settings>
        </Screen>
      </Screens>
    </Profile>
    <Profile Name ="SomeProfile">
      <Screens>
        <Screen Id="MyScreenId">
          <Settings>
            <Setting Name="Boring">
              <Paydirt>NOES you should not find this!!!</Paydirt>
            </Setting>
          </Settings>
        </Screen>
      </Screens>
    </Profile>
    <Profile Name ="SomeProfile">
      <Screens>
        <Screen Id="Boring">
          <Settings>
            <Setting Name="MySettingName">
              <Paydirt>NOES you should not find this!!!</Paydirt>
            </Setting>
          </Settings>
        </Screen>
      </Screens>
    </Profile>
    <Profile Name ="Boring">
      <Screens>
        <Screen Id="MyScreenId">
          <Settings>
            <Setting Name="MySettingName">
              <Paydirt>NOES you should not find this!!!</Paydirt>
            </Setting>
          </Settings>
        </Screen>
      </Screens>
    </Profile>
  </Profiles>
</ConfigurationRelease>

, .

C:\Sandbox\XPathInCE\XPathInCE\bin\Debug>XPathInCE MyXmlFile.xml ConfigurationRe
lease/Profiles/Profile[Name='MyProfileName']/Screens/Screen[Id='MyScreenId']/Set
tings/Setting[Name='MySettingName']
Considering element: ConfigurationRelease
Considering element: Profiles
Considering element: Profile
Considering element: Screens
Considering element: Screen
Considering element: Settings
Considering element: Setting
XPath match found!
Element Paydirt
Attributes
Element value: Good stuff
Considering element: Profile
Skipping
Considering element: Profile
Skipping
Considering element: Profile
Skipping
Press ENTER to exit

, CF 2.00.exe, , CE. , , , .

- , , .

+3

:

DataSet ds = new Dataset();
ds.ReadXml("C:\MyXmlFile.xml")

linq .

+2

Dataset - .

, XmlReader . , , , XML- XmlReader .

, , . CPU . , . 2 , . OOM . XmlSerializer, , OOM. , , .

0

, sax, , XML. , XML- .

, , , , , .

, .

, , , XML- . . . : XML, ( xpath ..). , ..

, libxml2 C, # ( ).

0

Source: https://habr.com/ru/post/1703358/


All Articles