tags:

views:

128

answers:

6

Somehow, using linq I can't test it with this CUF field in the beginning:

<NFe>
    <infNFe versao="1.0" Id="NFe0000000000">
        <ide>
             <cUF>35</cUF>
             <!--...-->
        </ide>
    </infNFe>
</NFe>

With the following code:

XDocument document = XDocument.Load(@"c:\nota.xml");
            var query = from NFe in document.Descendants("NFe")
                        select new
                        {
                            cuf = NFe.Element("infNFe").Element("ide").Element("cUF").Value
                        };

The whole XML loads into document (checked) but NFe.cuf gives me nothing. I guess the parameters inside the nodes are messing it up..

How do I get this "cuf" with linq?
What if I wanted the Id parameter in infNFe ?

--[EDIT]--

I had forgotten to give the "silly url in the beginning", what happens is that it is the NAMESPACE, (the non-displaying of the namespace of the xml in Firefox contributed)

Now this works:

        XNamespace ns = "http://www.portalfiscal.inf.br/nfe";
        XElement root = XElement.Load(@"c:\nota.xml");

        textBox1.Text = root.Element(ns + "infNFe").Element(ns + "ide").Element(ns + "cUF").Value;

Is there a way to set the namespace somewhere, and not needing to put it in every single field call ?

A: 

You could use XPath:

using System;
using System.Xml.Linq;
using System.Xml.XPath;

class Program
{
    static void Main(string[] args)
    {
        var doc = XDocument.Load(@"c:\nota.xml");
        var cuf = doc.XPathSelectElement("//cUF");
        if (cuf != null)
        {
            Console.WriteLine(cuf.Value);
        }

        var infNFe = doc.XPathSelectElement("//infNFe");
        if (infNFe != null)
        {
            var id = infNFe.Attribute("Id");
            if (id != null) 
            {
                Console.WriteLine(id.Value);
            }
        }

    }
}

given this XML:

<?xml version="1.0"?>
<NFe>
  <infNFe versao="1.0" Id="NFe0000000000">
    <ide>
      <cUF>35</cUF>
    </ide>
  </infNFe>
</NFe>
Darin Dimitrov
+1  A: 

You're looking at document.Descendants, which is all the elements inside the root.

document.Descendants in your case would contain infNFe, ide, cUF ... which is why you cannot find the root in the collection.

Try using document.Root instead.

Fiona Holder
It's impossible to use document.Root in-place in the query because returns a single node, whereas Descendants returns a collection of nodes. However the OP can use document.Root with a single-line of code as I've demonstrated in my answer.
Andy Shellam
Good point, I guess I didn't exapnd on how exactly you would use document.Root
Fiona Holder
+2  A: 

You don't really need that full LINQ query - a single one-liner will do:

string cuf = document.Root.Element("infNFe").Element("ide").Element("cUF").Value;
// cuf = 35

The same for the ID:

string id = document.Root.Element("infNFe").Attribute("Id").Value;
// id = NFe0000000000
Andy Shellam
Agreed, this really isn't a good use of linq.
Nix
A: 

try query.SingleOrDefault();

undertakeror
A: 

Actually, when running your code I don't see any problem. I've done the follwing:

XDocument document = XDocument.Load(@"c:\temp\nota.xml");
var query = from NFe in document.Descendants("NFe")
            select new
            {
                cuf = NFe.Element("infNFe").Element("ide").Element("cUF").Value,
                infId = NFe.Element("infNFe").Attribute("Id").Value
            };

foreach(var v in query)
    Console.WriteLine(v.cuf + " " + v.infId);

Given the following xml:

<NFe> 
<infNFe versao="1.0" Id="NFe0000000000"> 
<ide> 
<cUF>35</cUF> 
</ide>
</infNFe>
</NFe> 

It outputs:

35 NFe0000000000
klausbyskov
A: 

edit: Use an XElement, it's much easier.

Now you're using namespaces, so you need to specify those too with XNamespace

If you aren't sure where it's breaking, simply split your query into multiple lines like the below so that you can step through and determine where the error is occurring.

XNamespace ns = "http://www.somewebsite.com";
XElement root = XElement.Load(@"c:\nota.xml");
var infNFe = root.Element(ns + "infNFe");
var ide = infNFe.Element(ns + "ide");
var cUF = ide.Element(ns + "cUF");
var value = cUF.Value;

To clarify the namespace issue, if you have XML like

<a xmlns="namespace">
    <b>123</b>
</a>

then a.Element("b") doesn't exist. You need to interrogate the element b with namespace namespace. Just like namespaces anywhere else in C# - they are something like dimensions. You are looking in the right path but in the wrong dimension.

Kirk Broadhurst
Well, it worked, but do I have to put nd + "field" every time I call a field? can't I domehow mount a conventional one-liner where the namespace is set somewhere ? btw, Thank you
MarceloRamires
When I first started with LINQ and XML I asked a similar question, but in reality this way makes a lot of sense. In my experience you always need to specify the namespace. It's no big deal.
Kirk Broadhurst
*somehow*.. Yeah.. check the new edit. I've made the one-line code, with the given ns+field.. Doesn't seem too bad, since It's gonna be just a function.
MarceloRamires
That's how I'd do it.
Kirk Broadhurst