Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selecting namespaced XML node attributes with namespace alias instead of URI on an XElement

I'm trying to query out some information from a heavily namespaced XML document and am having some trouble finding attributes that are also namespaced.

The XML looks like:

<?xml version="1.0" encoding="utf-8" ?>
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns:skos="http://www.w3.org/2004/02/skos/core#"
    xmlns:geo="http://www.geonames.org/ontology#"
    xmlns:dc="http://purl.org/dc/terms/"
    xmlns:foaf="http://xmlns.com/foaf/0.1/"
    xmlns:void="http://rdfs.org/ns/void#">

    <geo:Country rdf:about="http://ontologi.es/place/AD" skos:notation="AD" rdfs:label="Andorra" />
    <geo:Country rdf:about="http://ontologi.es/place/AE" skos:notation="AE" rdfs:label="United Arab Emirates" />
    <geo:Country rdf:about="http://ontologi.es/place/AF" skos:notation="AF" rdfs:label="Afghanistan" />
    <geo:Country rdf:about="http://ontologi.es/place/AG" skos:notation="AG" rdfs:label="Antigua &amp; Barbuda" />
    <geo:Country rdf:about="http://ontologi.es/place/AI" skos:notation="AI" rdfs:label="Anguilla" />
    <geo:Country rdf:about="http://ontologi.es/place/AL" skos:notation="AL" rdfs:label="Albania" /> 
    ...

</rdf:RDF>

My goal is to create a list of objects that have a country code and a country name. Here's what works for me now:

XmlReader reader = XmlReader.Create(@"path/to/xml.xml");
XDocument root = XDocument.Load(reader);
XmlNameTable nameTable = reader.NameTable;

XmlNamespaceManager nsManager = new XmlNamespaceManager(nameTable);
nsManager.AddNamespace("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
nsManager.AddNamespace("rdfs", "http://www.w3.org/2000/01/rdf-schema#");
nsManager.AddNamespace("skos", "http://www.w3.org/2004/02/skos/core#");
nsManager.AddNamespace("geo", "http://www.geonames.org/ontology#");

var geoCountries = 
    from country in root.XPathSelectElements("./rdf:RDF/geo:Country", nsManager)
    select new {
        CountryCode = country.Attributes("{http://www.w3.org/2004/02/skos/core#}notation").First().Value,
        CountryName = country.Attributes("{http://www.w3.org/2000/01/rdf-schema#}label").First().Value
    };

This works fine, but I'd like to find the attributes using the namespace aliases, not the namespace URI (just because), or at least be able to lookup the URI using the alias. To try the latter idea, I eventually figured out I could do this:

country.Attributes(nsManager.LookupNamespace("skos") + "notation").First().Value

But I get an XmlException: The ':' character, hexadecimal value 0x3A, cannot be included in a name.

So then I tried:

country.Attributes("{" + nsManager.LookupNamespace("skos") + "}notation").First().Value

And then it works, but just seems like there could or should be an easier way, or rather, the {namespace}attribute syntax seems silly to me, like something that might be abstracted away in the framework.

  • So with all that, are there any shortcuts or easier ways to look up namespaced attributes?

I'd appreciate any feedback. Thanks!

like image 239
Cᴏʀʏ Avatar asked Dec 21 '22 02:12

Cᴏʀʏ


1 Answers

using Linq to xml

XNamespace skos = XNamespace.Get("http://www.w3.org/2004/02/skos/core#");
XNamespace geo = XNamespace.Get("http://www.geonames.org/ontology#");
XNamespace rdfs = XNamespace.Get("http://www.w3.org/2000/01/rdf-schema#");

XDocument rdf = XDocument.Load(new StringReader(xmlstr));
foreach(var country in rdf.Descendants(geo + "Country"))
{
    Console.WriteLine(
        country.Attribute(skos + "notation").Value + " "  + 
        country.Attribute(rdfs + "label").Value );
}
like image 139
L.B Avatar answered Dec 24 '22 02:12

L.B