how to select all desendent from xmlfile - linq

I have the following XML snippet:
<dependency>
<dependentAssembly dependencyType="install" allowDelayedBinding="true" size="92160">
<hash>
<dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<dsig:DigestValue>CPxsdsbvZSAAkmARkxa8ychL2aLZRc=</dsig:DigestValue>
</hash>
</dependentAssembly>
</dependency>
How to select this node using LINQ, or all decendent nodes for it:
<dsig:Transforms>
Thanks.

XDocument.Load("file.xml").Root.Descendants(XName.Get("dsig", "Transforms"));

Something like this should work:
XElement docElem = XElement.Load(pathToXml);
XNamespace ns = "http://www.w3.org/2000/09/xmldsig#";
// This assumes you know there will be exactly one "Transforms" element
XElement transforms = docElem.Descendants(ns + "Transforms").Single();
foreach (XElement transform in transforms.Elements()) {
// Do something with each Transform element
}
For this to work the complete XML (with namespace prefix declarations) must be loaded.

Related

Using nokogiri xpath to access nested elements within an xmlns

I'm new to nokogiri and am having trouble using xpath to access nested elements of an xml document with a specific xmlns.
Given the following code
#!/opt/chef/embedded/bin/ruby
require 'nokogiri'
doc = Nokogiri::XML.parse <<-XML
<?xml version="1.0" encoding="UTF-8" ?>
<domain xmlns="urn:jboss:domain:1.8">
<profiles>
<profile name="full">
<subsystem xmlns="urn:jboss:domain:datasources:1.2">
<datasources>
<datasource jndi-name="java:/Paulstestjndi" pool-name="pauls_ds" enabled="false">
<connection-url>jdbc:oracle:thin:#testhost1:80001paulstestinstance|jdbc:oracle:thin:#testhost2:80001paulstestinstance</connection-url>
</datasource>
</datasources>
</subsystem>
</profile>
</profiles>
</domain>
XML
datasources = doc.xpath('//datasources:datasource', 'datasources' => "urn:jboss:domain:datasources:1.2")
datasources.each do |datasource|
conn_url = datasource.xpath("connection-url")
puts "CLASS = #{conn_url.class}"
puts "No of Entries = #{conn_url.length}"
end
I am able to retrieve datasources using xpath but am unable to use xpath to access 'connection-url' for each datasource.
I have tried several xpath calls to achieve this the following are examples
conn_url = datasource.xpath("connection-url")
conn_url = datasource.xpath("//connection-url")
conn_url = datasource.xpath("//datasources:datasource/connection-url", 'datasources'=>"urn:jboss:domain:datasources:1.2")
But each seems to return an empty set of results.
What am I missing?
It’s a namespacing issue:
datasource.xpath(
'subsystem:connection-url',
'subsystem' => 'urn:jboss:domain:datasources:1.2')
#⇒ [#<... name="connection-url" namespace=...

JAXB Moxy getValueByXpath gives null

I want to see if a theme element exists with specified name in the following xml file.
input.xml
<data>
<artifacts>
<document id="efqw4eads">
<name>composite</name>
</document>
<theme id="1">
<name>Terrace</name>
</theme>
<theme id="2">
<name>Garage</name>
</theme>
<theme id="3">
<name>Reception</name>
</theme>
<theme id="4">
<name>Grade II</name>
</theme>
</artifacts>
</data>
I have the following code. return true statement of the method is never executed. answer always contains a null value.
public boolean themeExists(String name, Data data){
String expression = "artifacts/theme[name='"+name+"']/name/text()";
String answer = jaxbContext.getValueByXPath(data, expression, null, String.class);
if(answer == null || answer.equals("")){
return false;
}
return true;
}
This use case isn't currently supported by EclipseLink JAXB (MOXy). I have opened the following enhancement you can use to track our progress:
http://bugs.eclipse.org/413823
There is no <artifacts/> element you're look for in the first axis step. Your XPath expression should be something like
String expression = "data/theme[name='"+name+"']/name/text()";

Returning List<string> from XDocument

<dataList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<headers>
<header>Template name</header>
</headers>
<rows>
<row>
<data>Template1</data>
</row>
<row>
<data>Template2</data>
</row>
</rows>
</dataList>
XDocument xml = new XDocument();
xml = XDocument.Parse(xmlstringFromAbove);
List<string> list = (from c in xml.Elements("data")
select c.Value).ToList();
This code returns an empty list.
How can I get a list of strings containing Template1 and Template2 ?
The Elements method only returns immediate children, use Descendants instead:
var xml = XDocument.Parse(xmlstringFromAbove);
var list = (from c in xml.Descendants("data") select c.Value).ToList();

Use of text() function when using xPath in dom4j

I have inherited an application that parses xml using dom4j and xPath:
The xml being parsed is similar to the following:
<cache>
<content>
<transaction>
<page>
<widget name="PAGE_ID">WRK_REGISTRATION</widget>
<widget name="TRANS_DETAIL_ID">77145</widget>
<widget name="GRD_ERRORS" />
</page>
<page>
<widget name="PAGE_ID">WRK_REGISTRATION</widget>
<widget name="TRANS_DETAIL_ID">77147</widget>
<widget name="GRD_ERRORS" />
</page>
<page>
<widget name="PAGE_ID">WRK_PROCESSING</widget>
<widget name="TRANS_DETAIL_ID">77152</widget>
<widget name="GRD_ERRORS" />
</page>
</transaction>
</content>
</cache>
Individual Nodes are being searched using the following:
String xPathToGridErrorNode = "//cache/content/transaction/page/widget[#name='PAGE_ID'][text()='WRK_DNA_REGISTRATION']/../widget[#name='TRANS_DETAIL_ID'][text()='77147']/../widget[#name='GRD_ERRORS_TEMP']";
org.dom4j.Element root = null;
SAXReader reader = new SAXReader();
Document document = reader.read(new BufferedInputStream(new ByteArrayInputStream(xmlToParse.getBytes())));
root = document.getRootElement();
Node gridNode = root.selectSingleNode(xPathToGridErrorNode);
where xmlToParse is a String of xml similar to the excerpt provided above.
The code is trying to obtain the GRD_ERROR node for the page with the PAGE_ID and TRANS_DETAIL_ID provided in the xPath.
I am seeing an intermittent (~1-2%) failure (returned node is null) of this selectSingleNode request even though the requested node is in the xml being searched.
I know there are some gotchas associated with using text()= in xPath and was wondering if there was a better way to format the xPath string for this type of search.
From your snippets, there is a problem regarding GRD_ERRORS vs. GRD_ERRORS_TMP and WRK_REGISTRATION vs. WRK_DNA_REGISTRATION.
Ignoring that, I would suggest to rewrite
//cache/content/transaction/page
/widget[#name='PAGE_ID'][text()='WRK_DNA_REGISTRATION']
/../widget[#name='TRANS_DETAIL_ID'][text()='77147']
/../widget[#name='GRD_ERRORS_TEMP']
as
//cache/content/transaction/page
[widget[#name='PAGE_ID'][text()='WRK_REGISTRATION']]
[widget[#name='TRANS_DETAIL_ID'][text()='77147']]
/widget[#name='GRD_ERRORS']
Just because it makes the code, in my eyes, easier to read, and expresses what you seem to mean more clearly: “the page element that has children with these conditions, and then take the widget with this #name.” Or, if that is closer to how you think about it,
//cache/content/transaction/page/widget[#name='GRD_ERRORS']
[preceding-sibling::widget[#name='PAGE_ID'][text()='WRK_REGISTRATION']]
[preceding-sibling::widget[#name='TRANS_DETAIL_ID'][text()='77147']]

Problem with namespace and libxml when i use Xpath

i've got a problem when i'm using libxml with XPath. I want to parse an youtube playlist :
<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns='http://www.w3.org/2005/Atom'
xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/'
xmlns:media='http://search.yahoo.com/mrss/'
xmlns:batch='http://schemas.google.com/gdata/batch'
xmlns:yt='http://gdata.youtube.com/schemas/2007'
xmlns:gd='http://schemas.google.com/g/2005'
gd:etag='W/"Dk8DRn47eCp7ImA9WxRQGEk."'>
<id>tag:youtube,2008:user:andyland74:playlists</id>
<updated>2008-07-21T16:43:25.232Z</updated>
<category scheme='http://schemas.google.com/g/2005#kind'
term='http://gdata.youtube.com/schemas/2007#playlistLink'/>
<title>Playlists of andyland74</title>
<logo>http://www.youtube.com/img/pic_youtubelogo_123x63.gif</logo>
<link rel='related' type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74?v=2'/>
<link rel='alternate' type='text/html'
href='http://www.youtube.com/profile_play_list?user=andyland74'/>
<link rel='http://schemas.google.com/g/2005#feed'
type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists?v=2'/>
<link rel='http://schemas.google.com/g/2005#post'
type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists?v=2'/>
<link rel='http://schemas.google.com/g/2005#batch'
type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists/batch?v=2'/>
<link rel='self' type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists?...'/>
<link rel='service' type='application/atomsvc+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists?alt=...'/>
<author>
<name>andyland74</name>
<uri>http://gdata.youtube.com/feeds/api/users/andyland74</uri>
</author>
<generator version='2.0'
uri='http://gdata.youtube.com/'>YouTube data API</generator>
<openSearch:totalResults>3</openSearch:totalResults>
<openSearch:startIndex>1</openSearch:startIndex>
<openSearch:itemsPerPage>25</openSearch:itemsPerPage>
<entry gd:etag='W/"Dk8DRn47eCp7ImA9WxRQGEk."'>
<id>tag:youtube,2008:user:andyland74:playlist:8BCDD04DE8F771B2</id>
<published>2007-11-04T17:30:27.000-08:00</published>
<updated>2008-07-15T12:33:20.000-07:00</updated>
<app:edited xmlns:app='http://www.w3.org/2007/app'>2008-07-15T12:33:20.000-07:00</app:edited>
<category scheme='http://schemas.google.com/g/2005#kind'
term='http://gdata.youtube.com/schemas/2007#playlistLink'/>
<title>My New Playlist Title</title>
<summary>My new playlist Description</summary>
<content type='application/atom+xml;type=feed'
src='http://gdata.youtube.com/feeds/api/playlists/8BCDD04DE8F771B2?v=2'/>
<link rel='related' type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74?v=2'/>
<link rel='alternate' type='text/html'
href='http://www.youtube.com/view_play_list?p=8BCDD04DE8F771B2'/>
<link rel='self' type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists/8BCDD04DE8F771B2?v=2'/>
<link rel='edit' type='application/atom+xml'
href='http://gdata.youtube.com/feeds/api/users/andyland74/playlists/8BCDD04DE8F771B2?v=2'/>
<author>
<name>andyland74</name>
<uri>http://gdata.youtube.com/feeds/api/users/andyland74</uri>
</author>
<yt:countHint>9</yt:countHint>
</entry>
</feed>
when i use the following xpath expression "/feed", the xmlXPathEvalExpression say me that i doesnt find.
if i remove all the xmlns attributes of feed it works. How could i make it work even with xmlns attributes ?
i use libxml with objective-C
I ran into a similar issue when trying to use libxml-ruby to parse through xml. From http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/XPath.html:
To find nodes you must define the atom
namespace for libxml. One way to do
this is:
node = doc.find('atom:title', 'atom:http://www.w3.org/2005/Atom')
Alternatively, you can register the
default namespace like this:
doc.root.namespaces.default_prefix = 'atom' node = doc.find('atom:title')
Either way works, but registering makes sense if you're going to be using the methods a lot. Then you can just reference items like 'atom:title'.
I am using the XPathQuery wrapper around xmlXPathEvalExpression which makes it harder to go the xmlXpathRegisterNS route.
If you are querying for the fields directly, you probably do not care about the namespaces - it doesn't matter for my app. So, I just modified the XML before I process it.
NSString *xmlString = [[NSString alloc] initWithData:originalXMLData encoding:NSUTF8StringEncoding];
NSString *modifiedXMLString = [xmlString stringByReplacingOccurrencesOfString:#"xmlns=" withString:#"foobar="];
NSData *modifiedXMLData = [modifiedXMLString dataUsingEncoding:NSUTF8StringEncoding];
Now you can use modifiedXMLData in xmlXPathEvalExpression or PerformXMLXPathQuery if you use XPathQuery.
You didn't post your query code, but it sounds like you aren't registering the namespaces with your XpathContext. Here's the API docs for xmlXPathRegisterNS, I believe it will do what you're looking for. It won't let you register a default namespace, so you'll need to change your XPath expression to /feed:feed or the like.
To use a default namespace just register the namespace xlmns= and then use /xmlns:feed in your query.
After some research, I found the following solution that just works like NSXMLDocument path queries:
when xml documents declare a default namespace without a prefix, like
xmlns="..."
simple xpaths queries fail, like
xpath: /node
that's because xmlXPathEvalExpressionexpects some kind of default namespace prefix but there is none.
One approach is to fix the missing prefix (like GDataXML does) but that requires all xpaths to use this prefix, like
xpath: /__def_ns:node
But this is not how xpath's and NSXMLDocument works.
The following solution (based on a DDXMLNode) goes to the root node and scans for a namesepace without a prefix.
Then all nodes below are being traversed and if they belong to that namespace, it is being removed.
This is just like if there was no namespace in the first place.
- (void)fixNameSpace
{
xmlNodePtr nodePtr = (xmlNodePtr)self->genericPtr;
xmlNsPtr ns = nodePtr->nsDef;
xmlNsPtr defaultNs = NULL;
while(ns != NULL)
{
if (ns->prefix == NULL)
{
defaultNs = ns;
break;
}
ns = ns->next;
}
if (defaultNs)
[self resetDefaultNs:defaultNs];
}
- (void)resetDefaultNs:(xmlNsPtr)defaultNs
{
xmlNodePtr nodePtr = (xmlNodePtr)self->genericPtr;
xmlNsPtr ns = nodePtr->ns;
if (ns && ns == defaultNs)
xmlSetNs(nodePtr, NULL);
for (NSXMLNode* child in self.children)
[child resetDefaultNs:defaultNs];
}

Resources