Selecting elements with specific namespaced attributes - ruby

My problem is specifically about some trouble I'm having parsing an Inkscape (XML) file, but it's solution should be applicable to any XML doc, so I feel it's Stackoverflow relevant.
I'm trying to use the Nokogiri CSS selectors to get all the <g> elements that have the attribute inkscape:groupmode="layer". But the colon is causing the error:
Nokogiri::CSS::SyntaxError: unexpected ':' after 'inkscape'
My XML document looks like:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="744.09448819" height="1052.3622047" id="svg3720" version="1.1" inkscape:version="0.48.1 r9760" sodipodi:docname="test.svg">
<defs id="defs3722">
<inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 526.18109 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="744.09448 : 526.18109 : 1" inkscape:persp3d-origin="372.04724 : 350.78739 : 1" id="perspective3728"/>
</defs>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.35" inkscape:cx="375" inkscape:cy="634.28571" inkscape:document-units="px" inkscape:current-layer="g2818" showgrid="false" inkscape:window-width="550" inkscape:window-height="483" inkscape:window-x="66" inkscape:window-y="471" inkscape:window-maximized="0"/>
<metadata id="metadata3725">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1">
<rect style="fill:#d2e149;fill-opacity:1;stroke:none" id="rect2812" width="211.42857" height="128.57143" x="168.57143" y="215.21933" ry="64.285713"/>
</g>
<g inkscape:label="Layer 1 copy copy" inkscape:groupmode="layer" id="g2818">
<rect style="fill:#d2e149;fill-opacity:1;stroke:none" id="rect2820" width="211.42857" height="128.57143" x="145.71428" y="615.2193" ry="64.285713"/>
</g>
</svg>
My selector looks like:
nokogiri_document.css('[inkscape:groupmode="layer"]').to_html
I also tried replacing the colon with a pipe
How do I write the CSS selector to work on the inkscape:groupmode attribute...or for that matter any foo:bar attribute?

Use XPath, specifying the namespace for the g elements. Since your root element declares the xmlns:svg to be the same as the new default namespace (xmlns) you can use svg as your prefix:
require 'nokogiri'
doc = Nokogiri.XML(IO.read('contents.xml'))
layers = doc.xpath('//svg:g[#inkscape:groupmode="layer"]')
p layers.map{ |layer| layer['id'] }
#=> ["layer1", "g2818"]
Decoded, the above XPath says:
// - At any level of the document
svg:g - …find g elements with a namespace matching the svg namespace
[…] - …but only if the contents of this are met
#inkscape:groupmode - …there is an attribute (#) named groupmode with a namespace matching inkscape
="layer" - and the intrinsic value of this attribute is the text layer.
Alternatively, if you're just trying to read this file (and not manipulate and re-save it) you can use the gross-but-simplifying hack of removing all namespaces. In this case, your original code works simply:
doc.remove_namespaces!
p doc.css('g[groupmode="layer"]').map{ |g| g['id'] }
#=> ["layer1", "g2818"]

I suggest that you try to use XPath. Look at this snippet:
require 'nokogiri'
doc = Nokogiri::XML(File.read('your_file.xml'))
doc.xpath('//xmlns:g[starts-with(#inkscape:label, "Layer")]').size # => 2
Please pay attention at xmlns in XPath expression. Because XPath query looks for elements that are not in any namespace, you need to tell your XPath processor that you are looking for elements in given namespace. You can do this by several ways. I use most simple case - the using the default namespace in XPath query. Also you can define a custom namespace in the second argument of the XPath method call and use that in the query.

Related

How to use following in Xpath to get siblings in a Tag

I have following Structure: I am trying to build a robust method to extract the elements of FT1_19_0 of the FT1_19 Tag in the order they appear. However
in my results the elements are rearranged. How can i get my result in correct order.
//*/FT1_19/FT1_19_0[contains(../FT1_19_2,'I10') and
not(.=../following::FT1_19/FT1_19_0)]
The Result(Rearranged)
X50.0XXA
M76.891
M17.11
M23.303
<?xml version="1.0" encoding="UTF-8"?>
<root>
<FT1>
<FT1_1>1</FT1_1>
<FT1_4>20180920130000</FT1_4>
<FT1_5>20180924110101</FT1_5>
<FT1_6>CG</FT1_6>
<FT1_7>99203</FT1_7>
<FT1_9/>
<FT1_10>1.00</FT1_10>
<FT1_13>NPI</FT1_13>
<FT1_16>
<FT1_16_1>Gavin, Matthew, MD</FT1_16_1>
<FT1_16_3>22</FT1_16_3>
</FT1_16>
<FT1_19 NO="1">
<FT1_19_0>M76.891</FT1_19_0>
<FT1_19_2>I10</FT1_19_2>
</FT1_19>
<FT1_19 NO="2">
<FT1_19_0>M17.11</FT1_19_0>
<FT1_19_2>I10</FT1_19_2>
</FT1_19>
<FT1_19 NO="3">
<FT1_19_0>M23.303</FT1_19_0>
<FT1_19_2>I10</FT1_19_2>
</FT1_19>
<FT1_19 NO="4">
<FT1_19_0>X50.0XXA</FT1_19_0>
<FT1_19_2>I10</FT1_19_2>
</FT1_19>
</FT1>
</root>
Use this if you are using java:
List<WebElement> list = driver.findElements(By.xpath("//ft1_19//following::ft1_19_0"));
for(WebElement we:list) {
System.out.println(we.getText());
}

SLD Filter function if_then_else argument #2 - expected type Object

I'm facing a problem with the GeoServer SLD XML.
My XML code is as follows:
<Fill>
<CssParameter name="fill">
<ogc:Function name="if_then_else">
<ogc:Function name="isNull">
<ogc:PropertyName>LTE_RSRP</ogc:PropertyName>
</ogc:Function>
<ogc:Literal>#FF0000</ogc:Literal>
<ogc:Function name="Interpolate">
<ogc:PropertyName>LTE_RSRP</ogc:PropertyName>
<ogc:Literal>-80</ogc:Literal>
<ogc:Literal>#ff0000</ogc:Literal>
<ogc:Literal>-70</ogc:Literal>
<ogc:Literal>#00ff00</ogc:Literal>
<ogc:Literal>-60</ogc:Literal>
<ogc:Literal>#0000ff</ogc:Literal>
<ogc:Literal>color</ogc:Literal>
</ogc:Function>
</ogc:Function>
</CssParameter>
<CssParameter name="fill-opacity">0.3</CssParameter>
</Fill>
My intention is as follows:
If LTE_RSRP is null, fill with #FF0000.
Else, interpolate the color.
But when the above XML is applied, the following error occurs.
ERROR [geotools.rendering] - Filter Function problem for function if_then_else argument #2 - expected type Object
Here, argument #2 is the function Interpolate. (argument counting starts from 0, according to the geotools source code.) It seems that the return value of the function Interpolate is not an object.
Is this intentional? Or am I doing something wrong?
This is intentional - how could a function that interpolates a colour map return an object? What you want to do can be done using Rules and Filters so something (untested) like this should work:
<Rule>
<ogc:Filter>
<ogc:PropertyIsNull>
<ogc:PropertyName>LTE_RSRP</ogc:PropertyName>
</ogc:PropertyIsNull>
</ogc:Filter>
<ogc:PolygonSymbolizer>
....
<Fill>
....
</Rule>
<Rule>
<ElseFilter/>
<PolygonSymbolizer>
....
<Fill>
<ogc:Function name="Interpolate">
<ogc:PropertyName>LTE_RSRP</ogc:PropertyName>
<ogc:Literal>-80</ogc:Literal>
<ogc:Literal>#ff0000</ogc:Literal>
<ogc:Literal>-70</ogc:Literal>
<ogc:Literal>#00ff00</ogc:Literal>
<ogc:Literal>-60</ogc:Literal>
<ogc:Literal>#0000ff</ogc:Literal>
<ogc:Literal>color</ogc:Literal>
</ogc:Function>
....

KML exported from Maps fails validation against its own schema

I imported an Earth model into My Maps, then exported it to a KMZ. I unzipped the KMZ and ran the resulting doc.kml through a a validator (XmlValidator) against the XSD at http://schemas.opengis.net/kml/2.2.0/ogckml22.xsd.
The response?
C:\Users\Bugmagnet\Downloads\XmlValidate-master>bin\xv.bat -v -kmz ..\doc.kml
Check: ..\doc.kml
http://www.opengis.net/kml/2.2
ERROR: SAXParseException org.xml.sax.SAXParseException; lineNumber: 3319; columnNumber: 38; cvc-complex-type.2.4.a:
Invalid content was found starting with element 'Style'. One of '{"http://www.opengis.net/kml/2.2":AbstractFeatureGroup, "http://www.opengis.net/kml/2.2":DocumentSimpleExtensionGroup, "http://www.opengis.net/kml/2.2":DocumentObjectExtensionGroup}' is expected.
Line: 3319, column: 38
3319: <Style id="line-000000-1-normal">***
ERROR: SAXParseException org.xml.sax.SAXParseException; lineNumber: 3319; columnNumber: 38; cvc-complex-type.2.4.a:
Invalid content was found starting with element 'Style'. One of '{"http://www.opengis.net/kml/2.2":AbstractFeatureGroup, "http://www.opengis.net/kml/2.2":DocumentSimpleExtensionGroup, "http://www.opengis.net/kml/2.2":DocumentObjectExtensionGroup}' is expected.
Line: 3319, column: 38
Errors: 2 Warnings: 0 Files: 1 Time: 3659 ms
Valid files 0/1 (0%)
Is this important? Will it bite me later? What, if anything, can or should be done?
I'm asking because I'm using the KML exported from Maps as a template for generating KML programmatically for use in Maps.
Strangely, the first instance of the markup <Style id="line-000000-1-normal"> is not on line 3319 but on 4022 being
<Style id='line-000000-1-normal'>
<LineStyle>
<color>ff000000</color>
<width>1</width>
</LineStyle>
</Style>
Line 3199 is part way through a Placemark, on the , viz
<Placemark>
<name>LPVGDatumLutID {133}- Swan Hill</name>
<description>
<![CDATA[Log Provider [10] Google Analytics V3]]>
</description>
<styleUrl>#poly-000000-1-76</styleUrl>
<ExtendedData>
</ExtendedData>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<tessellate>1</tessellate>
<coordinates>143.5614,-35.250688,0.0 143.555643,-35.250811,0.0 143.549902,-35.25118,0.0 143.544192,-35.251793,0.0 143.538529,-35.25264899999999,0.0 143.532928,-35.253746,0.0 143.527406,-35.25508000000001,0.0 143.521976,-35.256649,0.0 143.516654,-35.258447,0.0 143.511454,-35.26046899999999,0.0 143.506391,-35.26271100000001,0.0 143.501478,-35.265166,0.0 143.496729,-35.267828,0.0 143.492156,-35.270688,0.0 143.487773,-35.27373999999999,0.0 143.483592,-35.276975,0.0 143.479623,-35.280383,0.0 143.475877,-35.283957,0.0 143.472366,-35.287686,0.0 143.469098,-35.29155900000001,0.0 143.466083,-35.295567000000005,0.0 143.463328,-35.299698,0.0 143.460842,-35.30394100000001,0.0 143.458631,-35.308284,0.0 143.456702,-35.312715,0.0 143.455059,-35.317223,0.0 143.453707,-35.32179500000001,0.0 143.45265,-35.326419,0.0 143.451892,-35.331081,0.0 143.451433,-35.335769,0.0 143.451276,-35.34047000000001,0.0 143.45142,-35.345172,0.0 143.451866,-35.349861,0.0 143.452613,-35.354524,0.0 143.453657,-35.35914900000001,0.0 143.454998,-35.363723,0.0 143.45663,-35.368234,0.0 143.458549,-35.372668999999995,0.0 143.460751,-35.377016000000005,0.0 143.46322900000004,-35.381263000000004,0.0 143.465977,-35.385398,0.0 143.468986,-35.389411,0.0 143.47224900000003,-35.39328900000001,0.0 143.475757,-35.397023,0.0 143.479501,-35.400601,0.0 143.483469,-35.404015,0.0 143.487652,-35.407255000000006,0.0 143.492037,-35.410312,0.0 143.496612,-35.413178,0.0 143.501366,-35.415844,0.0 143.506285,-35.418304,0.0 143.511355,-35.42055,0.0 143.516563,-35.422577,0.0 143.521894,-35.424378999999995,0.0 143.527334,-35.42595,0.0 143.532867,-35.427287,0.0 143.538479,-35.428386,0.0 143.544154,-35.429244,0.0 143.549876,-35.429859,0.0 143.55563,-35.430228,0.0 143.5614,-35.430352,0.0 143.56717,-35.430228,0.0 143.572924,-35.429859,0.0 143.578646,-35.429244,0.0 143.584321,-35.428386,0.0 143.589933,-35.427287,0.0 143.595466,-35.42595,0.0 143.600906,-35.424379,0.0 143.606237,-35.422577,0.0 143.611445,-35.42055,0.0 143.616515,-35.418304000000006,0.0 143.621434,-35.41584400000001,0.0 143.626188,-35.413178,0.0 143.630763,-35.410312,0.0 143.635148,-35.407255000000006,0.0 143.639331,-35.404015,0.0 143.643299,-35.400601,0.0 143.647043,-35.397023,0.0 143.650551,-35.393289,0.0 143.653814,-35.389411,0.0 143.656823,-35.385398,0.0 143.659571,-35.381263000000004,0.0 143.662049,-35.377016000000005,0.0 143.664251,-35.372669,0.0 143.66617,-35.368234,0.0 143.667802,-35.363723,0.0 143.669143,-35.35914900000001,0.0 143.670187,-35.354524,0.0 143.670934,-35.349861000000004,0.0 143.67138,-35.345172,0.0 143.671524,-35.34047000000001,0.0 143.671367,-35.335769000000006,0.0 143.670908,-35.331081,0.0 143.67015,-35.32641900000001,0.0 143.669093,-35.321795,0.0 143.667741,-35.317223,0.0 143.666098,-35.312715,0.0 143.664169,-35.308284,0.0 143.661958,-35.30394100000001,0.0 143.659472,-35.29969799999999,0.0 143.656717,-35.295567000000005,0.0 143.653702,-35.291559,0.0 143.650434,-35.287686,0.0 143.646923,-35.283957,0.0 143.643177,-35.280383,0.0 143.639208,-35.276975,0.0 143.635027,-35.273740000000004,0.0 143.630644,-35.270688,0.0 143.626071,-35.267828,0.0 143.621322,-35.265166,0.0 143.616409,-35.262710999999996,0.0 143.611346,-35.260469,0.0 143.606146,-35.258447,0.0 143.600824,-35.256649,0.0 143.595394,-35.25508000000001,0.0 143.589872,-35.253746,0.0 143.584271,-35.25264899999999,0.0 143.57860800000003,-35.251793,0.0 143.572898,-35.25118,0.0 143.567157,-35.250811,0.0 143.5614,-35.250688,0.0</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
LATER
More weirdness: I imported the kml into Fusion Charts and then exported it. The KML now has the style information before the placemarks, and validates perfectly.
Solution: Put the style information first.
<?xml version='1.0' encoding='UTF-8'?>
<kml xmlns='http://www.opengis.net/kml/2.2'>
<Document>
<name>doc</name>
<Style id='Style2-point-1'>
<IconStyle>
<color>ff0000ff</color>
<scale>1.0</scale>
<Icon>
<href>http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png</href>
</Icon>
</IconStyle>
<LabelStyle>
<scale>0.0</scale>
</LabelStyle>
<BalloonStyle>
<text>$[description]</text>
</BalloonStyle>
</Style>
<Style id='Style2-point-1-hover'>
<IconStyle>
<color>ff0000ff</color>
<scale>1.0</scale>
<Icon>
<href>http://maps.google.com/mapfiles/kml/shapes/placemark_circle.png</href>
</Icon>
</IconStyle>
<BalloonStyle>
<text>$[description]</text>
</BalloonStyle>
</Style>
<StyleMap id='Style2-point-1-map'>
<Pair>
<key>normal</key>
<styleUrl>#Style2-point-1</styleUrl>
</Pair>
<Pair>
<key>highlight</key>
<styleUrl>#Style2-point-1-hover</styleUrl>
</Pair>
</StyleMap>
<Placemark>
<name>LPVGDatumLutID {11}- Canberra</name>
<snippet/>
<description>
<![CDATA[<div class="googft-info-window">
<b>description:</b> Log Provider [10] Google Analytics V3<br>
<b>name:</b> LPVGDatumLutID {11}- Canberra
</div>]]></description>
<styleUrl>#Style2-polygon-3-map</styleUrl>
<ExtendedData/>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>148.836481,-35.026301,0.0 148.833751,-35.028007,0.0 148.816238,-35.040183,0.0 148.799522,-35.053091,0.0 148.783649,-35.066695,0.0 148.768662,-35.080959,0.0 148.754603,-35.095843,0.0 148.74151,-35.111308,0.0 148.729419,-35.127311,0.0 148.718365,-35.143808,0.0 148.708377,-35.160755,0.0 148.699483,-35.178105,0.0 148.691709,-35.195812,0.0 148.685076,-35.213826,0.0 148.679604,-35.2321,0.0 148.675308,-35.250581,0.0 148.672201,-35.269222,0.0 148.670291,-35.287969,0.0 148.669585,-35.306772,0.0 148.670086,-35.32558,0.0 148.671794,-35.34434,0.0 148.674704,-35.363002,0.0 148.678809,-35.381513,0.0 148.684099,-35.399824,0.0 148.69056,-35.417884,0.0 148.698174,-35.435644,0.0 148.706923,-35.453053,0.0 148.716782,-35.470065,0.0 148.727726,-35.486632,0.0 148.739723,-35.502709,0.0 148.752743,-35.518252,0.0 148.766749,-35.533217,0.0 148.781704,-35.547563,0.0 148.797566,-35.561251,0.0 148.814293,-35.574242,0.0 148.831838,-35.586501,0.0 148.850153,-35.597994,0.0 148.869187,-35.608688,0.0 148.888889,-35.618555,0.0 148.909204,-35.627566,0.0 148.930075,-35.635698,0.0 148.951446,-35.642927,0.0 148.973256,-35.649233,0.0 148.995445,-35.654599,0.0 149.017952,-35.659009,0.0 149.040715,-35.662453,0.0 149.063669,-35.664919,0.0 149.086753,-35.666401,0.0 149.104176,-35.666774,0.0 149.1099,-35.666896,0.0 149.133047,-35.666401,0.0 149.156131,-35.664919,0.0 149.179085,-35.662453,0.0 149.201848,-35.659009,0.0 149.224355,-35.654599,0.0 149.246544,-35.649233,0.0 149.268354,-35.642927,0.0 149.289725,-35.635698,0.0 149.310596,-35.627566,0.0 149.330911,-35.618555,0.0 149.350613,-35.608688,0.0 149.369647,-35.597994,0.0 149.387962,-35.586501,0.0 149.405507,-35.574242,0.0 149.422234,-35.561251,0.0 149.438096,-35.547563,0.0 149.453051,-35.533217,0.0 149.467057,-35.518252,0.0 149.480077,-35.502709,0.0 149.492074,-35.486632,0.0 149.503018,-35.470065,0.0 149.512877,-35.453053,0.0 149.521626,-35.435644,0.0 149.52924,-35.417884,0.0 149.535701,-35.399824,0.0 149.540991,-35.381513,0.0 149.545096,-35.363002,0.0 149.548006,-35.34434,0.0 149.549714,-35.32558,0.0 149.550215,-35.306772,0.0 149.549509,-35.287969,0.0 149.547599,-35.269222,0.0 149.544492,-35.250581,0.0 149.540196,-35.2321,0.0 149.537488,-35.223056,0.0 149.534724,-35.213826,0.0 149.528091,-35.195812,0.0 149.520317,-35.178105,0.0 149.511423,-35.160755,0.0 149.501435,-35.143808,0.0 149.490381,-35.127311,0.0 149.47829,-35.111308,0.0 149.465197,-35.095843,0.0 149.451138,-35.080959,0.0 149.436151,-35.066695,0.0 149.420278,-35.053091,0.0 149.403562,-35.040183,0.0 149.386049,-35.028007,0.0 149.367787,-35.016595,0.0 149.348826,-35.005979,0.0 149.329217,-34.996186,0.0 149.309014,-34.987245,0.0 149.288271,-34.979178,0.0 149.267046,-34.972008,0.0 149.245395,-34.965755,0.0 149.223377,-34.960435,0.0 149.201052,-34.956062,0.0 149.178481,-34.952648,0.0 149.155724,-34.950204,0.0 149.132843,-34.948734,0.0 149.1099,-34.948244,0.0 149.104176,-34.948367,0.0 149.086957,-34.948734,0.0 149.064076,-34.950204,0.0 149.041319,-34.952648,0.0 149.018748,-34.956062,0.0 148.996423,-34.960435,0.0 148.974405,-34.965755,0.0 148.952754,-34.972008,0.0 148.931529,-34.979178,0.0 148.910786,-34.987245,0.0 148.890583,-34.996186,0.0 148.870974,-35.005979,0.0 148.852013,-35.016595,0.0 148.836481,-35.026301,0.0</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
</Document>
</kml>

Seperate XML content from a single XML file using XQuery

I have a XML file which contains multiple XML nodes. I would like to separate two XML notes and store them in separate variables. How would I write this functionality with XQuery? I have added my XML file below. Inside the XML file I have a division root element, Dive and top-song are two child elements. Now I want to read the Dive XML content in one variable and top-song content in another variable. Can any one please help me to sort out this issue?
<?xml version="1.0" encoding="UTF-8"?>
<division>
<Dive ID="2"><!-- I want this node in one variable -->
<DiverFName>Joe</DiverFName>
<DiverLName>Diver</DiverLName>
<Number>2</Number>
<Divedate>1998-03-30</Divedate>
<Country ID="1">Bahamas</Country>
<City ID="2">Freeport</City>
<Place ID="2">
<Site>South Pass</Site>
<Lat>24.865062</Lat>
<Lon>-77.871094</Lon>
</Place>
<Divetime>36.00</Divetime>
<Depth Scale="METRIC">5.48</Depth>
<Buddy IDs="2" Names="Tim Diver" />
<Comments>Great dive, saw 5 Caribbean Reef Sharks. Performed compass navigation skills for Scuba Diver certification.</Comments>
<Water>Salt</Water>
<Entry>Boat</Entry>
<Divetype>Research</Divetype>
<Tanktype>Alu</Tanktype>
<Tanksize>11.43</Tanksize>
<PresS>179.26</PresS>
<PresE>82.73</PresE>
<Gas>Air</Gas>
<Weather>Clear</Weather>
<UWCurrent>Medium Current</UWCurrent>
<MarineLife>
<Animal>
<Type>Nurse Shark</Type>
<Abundance>1</Abundance>
<Size>3 ft</Size>
<Description>Dormant on the bottom, not swimming.</Description>
<Image>
<Filename></Filename>
<Path></Path>
<Caption></Caption>
</Image>
</Animal>
<Animal>
<Type>Blue Tang Surgeonfish</Type>
<Abundance>25+</Abundance>
<Size>4 in</Size>
<Description>Blue with white "scalpel" near base </descreption>
<Image>
<Filename></Filename>
<Path></Path>
<Caption></Caption>
</Image>
</Animal>
</MarineLife>
</Dive>
<top-song><!-- I want this node in another variable -->
<title >Try Again</title>
<artist >Aaliyah</artist>
<weeks last="2008-06-17">
<week>2008-06-17</week>
</weeks>
<album> The
Album</album>
<released>February 29, 20008</released>
<formats>
<format>CD</format>
<format>12 single</format>
</formats>
<recorded>january2012</recorded>
<genres>
<genre>R&B</genre>
</genres>
<lengths>
<length>4:04</length>
</lengths>
<label>Blackground</label>
<writers>
<writer></writer>
<writer></writer>
</writers>
<producers>
<producer></producer>
</producers>
<descr>
<p>hai hello</p>
</descr>
</top-song>
</division>
It's not clear what you're trying to accomplish on a high level, but you can select those elements with some simple XQuery/Xpath:
let $dive := doc('mydoc.xml')/division/Dive
let $top-song := doc('mydoc.xml')/division/top-song
However, just looking at the document it's clear that these two elements are in totally unrelated schemas, and as a general recommendation for MarkLogic, they should probably each be separated before ingestion and inserted as separate documents.

NSXMLDocument, nodesForXPath with namespaces

I want to get a set of elements from a xml-file, but as soon the the elements involve namespaces, it fails.
This is a fragment of the xml file:
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
version="1.0" creator="Groundspeak Pocket Query"
xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.groundspeak.com/cache/1/0 http://www.groundspeak.com/cache/1/0/cache.xsd"
xmlns="http://www.topografix.com/GPX/1/0">
<name>My Finds Pocket Query</name>
<desc>Geocache file generated by Groundspeak</desc>
<author>Groundspeak</author>
<email>contact#groundspeak.com</email>
<time>2010-09-15T16:18:55.9846906Z</time>
<keywords>cache, geocache, groundspeak</keywords>
<bounds minlat="41.89687" minlon="5.561883" maxlat="70.669967" maxlon="25.74735" />
<wpt lat="62.244933" lon="25.74735">
<time>2010-01-11T08:00:00Z</time>
<name>GC22W1T</name>
<desc>Kadonneet ja karanneet by ooti, Traditional Cache (1.5/2)</desc>
<url>http://www.geocaching.com/seek/cache_details.aspx?guid=4af28fe9-401b-44df-b058-5fd5399fc083</url>
<urlname>Kadonneet ja karanneet</urlname>
<sym>Geocache Found</sym>
<type>Geocache|Traditional Cache</type>
<groundspeak:cache id="1521507" available="True" archived="False" xmlns:groundspeak="http://www.groundspeak.com/cache/1/0">
<groundspeak:name>Kadonneet ja karanneet</groundspeak:name>
<groundspeak:placed_by>ooti</groundspeak:placed_by>
<groundspeak:owner id="816431">ooti</groundspeak:owner>
<groundspeak:type>Traditional Cache</groundspeak:type>
<groundspeak:container>Small</groundspeak:container>
<groundspeak:difficulty>1.5</groundspeak:difficulty>
<groundspeak:terrain>2</groundspeak:terrain>
<groundspeak:country>Finland</groundspeak:country>
<groundspeak:state>
</groundspeak:state>
<groundspeak:short_description html="True">
</groundspeak:short_description>
<groundspeak:encoded_hints>
</groundspeak:encoded_hints>
<groundspeak:travelbugs />
</groundspeak:cache>
</wpt>
</gpx>
I want to get all the grounspeak:cache elements, but neither //groundspeak:cache nor //cache seems to return anything.
NSArray *caches = [self.xml nodesForXPath:#"//cache" error:&error];
Any clue?
Edit: Are there any cocoa-based software out there, where I can load my xml and test different xpaths? I'm quite new to objective-c and cocoa, so it would be nice to check that it is really my xpath that is wrong..
This //cache means: a descendant element under no namespace (or empty namespace)
Your groundspeak:cache element is under a namespace URI http://www.groundspeak.com/cache/1/0.
So, if you can't declare a namespace-prefix binding (I think you can't with cocoa...), you could use this XPath expression:
//*[namespace-uri()='http://www.groundspeak.com/cache/1/0' and
local-name()='cache']
If you don't want to be so strict about namespace...
//*[local-name()='cache']
But this last is a bad practice, because you could end up selecting wrong nodes, and because when dealing with XML, your tool should support namespaces.
As proof, this stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:copy-of select="//*[namespace-uri() =
'http://www.groundspeak.com/cache/1/0' and
local-name() = 'cache']"/>
</xsl:template>
</xsl:stylesheet>
Output:
<groundspeak:cache id="1521507" available="True" archived="False"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.topografix.com/GPX/1/0"
xmlns:groundspeak="http://www.groundspeak.com/cache/1/0">
<groundspeak:name>Kadonneet ja karanneet</groundspeak:name>
<groundspeak:placed_by>ooti</groundspeak:placed_by>
<groundspeak:owner id="816431">ooti</groundspeak:owner>
<groundspeak:type>Traditional Cache</groundspeak:type>
<groundspeak:container>Small</groundspeak:container>
<groundspeak:difficulty>1.5</groundspeak:difficulty>
<groundspeak:terrain>2</groundspeak:terrain>
<groundspeak:country>Finland</groundspeak:country>
<groundspeak:state></groundspeak:state>
<groundspeak:short_description html="True"></groundspeak:short_description>
<groundspeak:encoded_hints></groundspeak:encoded_hints>
<groundspeak:travelbugs />
</groundspeak:cache>
You need to add a new namespace attribute to the root node of your document, defining a prefix that you can use when querying the children:
NSXMLDocument *xmldoc = ...
NSXMLElement *namespace = [NSXMLElement namespaceWithName:#"mns" stringValue:#"http://mynamespaceurl.com/mynamespace"];
[xmldoc.rootElement addNamespace:namespace];
then when you query things later, you can use that prefix to refer to the namespace:
NSArray * caches = [xmldoc.rootElement nodesForXPath:#"//mns:caches" error:&error];
//groundspeak:cache should work. You might need a namespace-uri setting as well

Resources