简体   繁体   中英

Error on querying element using LINQ to XML

This is a small section of a XML file I have.(see below).

I'm able to read what I need, like I can get the type and message etc. however in one of the PreflightResultEntry section there is a set of elements called Var I need the " <Var name="NumPages">8</Var> "

 --     
 <PreflightResultEntry type="GeneralDocInfo">
    <PreflightResultEntryMessage xml:lang="en-US">
        <Message>457834a.pdf </Message>
        <StringContext>
            <BaseString>%FileInfo%</BaseString>
            <Const name="Category">GeneralDocInfo</Const>
            <Const name="ActionID">-1</Const>
            <Instance>
                <Var name="FileInfo">
                    <Var name="DIPath">/V/PitStop/Testing/Mike/Processed Docs on Success/457834a.pdf</Var>
                    <Var name="CreationDate">D:20120724153648-05'00'</Var>
                    <Var name="ModDate">D:20120725134534-04'00'</Var>
                    <Var name="Producer">Adobe PDF Library 10.0</Var>
                    <Var name="Creator">Acrobat PDFMaker 10.1 for Word</Var>
                    <Var name="Author">DOL Comments</Var>
                    <Var name="Title"/>
                    <Var name="Subject"/>
                    <Var name="Keywords"/>
                    <Var name="Trapped">1</Var>
                    <Var name="NumPages">8</Var>
                    <Var name="Major">1</Var>
                    <Var name="Minor">5</Var>
                    <Var name="WasRepairedOnOpen">0</Var>
                    <Var name="IsLinearized">0</Var>
                    <Var name="ContainsThumbnails">0</Var>
                    <Var name="LeftToRightReading">1</Var>
                    <Var name="ContainsJobTicket">0</Var>
                    <Var name="EncryptionType">1</Var>
                    <Var name="Permissions">-1</Var>
                    <Var name="PrinergyTraps">3</Var>
                </Var>
                <Location page="-1"/>
            </Instance>
        </StringContext>
    </PreflightResultEntryMessage>
</PreflightResultEntry>
      ---

here what I have got that works for Messages and types

  List<PitStopMessage> messages = XDocument.Load(file)
      .Descendants("PreflightResultEntryMessage")
      .Where(x => x.Parent != null )
      .Select(x => new PitStopMessage()
      {
          message = x.Element("Message").Value,
          type = x.Parent.Attribute("type").Value,
          xmllevel = x.Parent.Attribute("level") != null ? x.Parent.Attribute("level").Value : String.Empty,
          link = 0
      }).ToList();

I need a new query to the elements var only if it exits in the parent element PreflightResultEntry

here what I have so far but its giving me a error "Object reference not set to an instance of an object." which is telling what I'm looking for (elements) don't exist.

 List<PitStopPages> messages = XDocument.Load(file)
     .Descendants("PreflightResultEntryMessage")
     .Where(x => x.Parent != null && x.Parent.Attribute("type").Value == "GeneralDocInfo" && x.Parent.Element("Var").Value == "NumPages")
     .Select(x => new PitStopPages()
     {
         Pages = x.Parent.Attribute("name").Value
     }).ToList();

I suggest using XPath to select the node you want. You can use the method XPathSelectElements and pass in your XPath . If you need to select only one node, you can use XPathSelectElement (without 's') instead.

In your situation, I think the XPath should be: /PreflightResultEntry//Var[@name='NumPages']

You can test the XPath here .

Let me expand on what @AnhTriet suggested,

var xml = new XmlDocument();

xml.LoadXml(str);  // suppose that str string contains your xml

var xnList = xml.SelectNodes("/PreflightResultEntry//Var[@name='NumPages']");

foreach (XmlNode xn in xnList)
{
    Console.WriteLine(xn.InnerText); //this should print the 8
}

.NET Fiddle

To be able to use the XPathSelectElement method you need to load first the xml using the XDocument class

So, it would be something like this:

var xml = XDocument.Load(file);

XmlNode node = xml.XPathSelectElement("/PreflightResultEntry//Var[@name='NumPages']");

Console.WriteLine(node.InnerText);

If you logically read through your query, you might spot the mistake.

Your query is trying to find:

  • An element called PreflightResultEntryMessage
  • Where its parent has a type attribute of GeneralDocInfo
  • Where its parent element's first child named Var has the value NumPages
  • Get the parent element's name attribute value

The issue is the last two parts. Parent in all your cases is the PreflightResultEntry element. PreflightResultEntry does not have any child Var element, no Var elements have the value NumPages , and PreflightResultEntry has no name attribute. Any one of these would cause a null reference exception (the exception you're seeing).

It's probably best to approach this from the top down rather than finding an element and then looking back up to its parent. So:

  • Find an element called PreflightResultEntry with a type attribute of GeneralDocInfo
  • Get a descendant Var element has a name attribute of NumPages

So:

var numPages = (int)XDocument.Load(file)
        .Descendants("PreflightResultEntry")
        .Where(x => (string) x.Attribute("type") == "GeneralDocInfo")
        .Descendants("Var")
        .Single(x => (string) x.Attribute("name") == "NumPages");

See this fiddle for a working demo.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM