Finding namespace of a given Element using VTD-XML - vtd-xml

For my application I only need to determine the namespace of the root node, so ideally I would like to execute a single operation to get this namespace.
I have code that uses an XPath to get all of the namespaces declared (/*/namespace::*), but then I have to go through them all and do vn.toRawString for each one to compare it to my prefix, which I would like to avoid.
I'm sure I'm missing something obvious here, but what is the best way to get the namespace of a given element, since xmlns: attributes are not considered in getAttrValNS ?
String elementName = vn.toRawString(vn.getCurrentIndex());
String prefix = prefix(elementName);
String localName = localName(elementName);
QName rootQName;
if (prefix == null) {
rootQName = new QName(localName);
} else {
int nsIndex = vn.getAttrValNS("xmlns", prefix);
// Can't find index because xmlns attributes are not included
String namespace = vn.toRawString(nsIndex);
rootQName = new QName(namespace, localName);
}
Is there a simple XPath that will just give me the namespace of the root node, not ALL namespaces DECLARED on the root node?

AutoPilot ap = new AutoPilot(vn);
ap.selectXPath("namespace-uri(.)");
String ns = ap.evalXPathToString();

Related

Apache Ignite : Ignite Repository query with "IN" clause, returns no records

I am using Apache Ignite as the back-end data store in a SpringBoot Application.
I have a requirement where I need to get all the entities whose name matches one of the names from a set of names.
Hence i am trying to get it implemented using a #Query configuration and a method named findAllByName(Iterable<String> names)as below:
Here on the Query, I am trying to use the 'IN' clause and want to pass an array of names as an input to the 'IN' clause.
#RepositoryConfig(cacheName = "Category")
public interface CategoryRepository extends IgniteRepository<Category, Long>
{
List<Category> findByName(String name);
#Query("SELECT * FROM Category WHERE name IN ( ? )")
Iterable<Category> findAllByName(Iterable<String> names); // this method always returns empty list .
}
In this the method findAllByName always returns empty list, even when ignite has Categories for which the name field matches the data passed in the query.
I am unable to figure out if there is a problem with the Syntax or the query of the method signature or the parameters.
Please try using String[] names instead for supplying parameters.
UPDATE: I have just checked the source, and we don't have tests for such scenario. It means that you're on uncharted territory even if it is somehow possible to get to work.
Otherwise looks unsupported currently.
I know your question is more specific to Spring Data Ignite feature. However, as an alternate, you can achieve it using the SqlQuery abstraction of Ignite.
You will form your query like this. I have pasted the sample below with custom sql function inSet that you will write. Also, the below tells how this is used in your sql.
IgniteCache<String, MyRecord> cache = this.ignite
.cache(this.environment.getProperty(Cache.CACHE_NAME));
String sql = "from “my-ignite-cache”.MyRecord WHERE
MyRecord.city=? AND inSet(?, MyRecord.flight)"
SqlQuery<String, MyRecord> sqlQuery = new SqlQuery<>(MyRecord.class,
sql);
sqlQuery.setArgs(MyCity, [Flight1, Flight2 ] );
QueryCursor<Entry<String, MyRecord>> resultCursor = cache.query(sqlQuery);
You can iterate the result cursor to do something meaningful from the extracted data.
resultCursor.forEach(e -> {
MyRecord record = e.getValue();
// do something with result
});
Below is the Ignite Custom Sql function which is used in the above Query - this will help in replicating the IN clause feature.
#QuerySqlFunction
public static boolean inSet(List<String> filterParamArgIds, String id) {
return filterParamArgIds.contains(id);
}
And finally, as a reference MyRecord referred above can be defined something like this.
public class MyRecord implements Serializable {
#QuerySqlField(name = "city", index = true)
private String city;
#QuerySqlField(name = "flight", index = true)
private String flight;
}

How iterate all Property of a node and update the value of each property and save in repository in cq5

My cq5 Content Structure is....
Content
---mywebsite
------base
-----us
--- en
----pageOne
----pageTwo
----pageThree
----pageFour
----cq:content
----par
----pageFourNew
"pageFourNew" has around 500 Properties.
Now I need to get all the properties of "pageFourNew" and to update their value.
For example if I have:
property=prop1
value = prop1 value
I want to do value = value+"some string value append" and save it on the repository.
I want to do this in a programmatically way.
Please share if you have any solution or idea.
You can use PropertyIterator to iterate through all the properties, setProperty() method of node api to set the new value and jcr session to persist the value to get this done. Sample code:
PropertyIterator propertyIterator = pageFourNew.getProperties();
while (propertyIterator.hasNext()) {
Property property = propertyIterator.nextProperty();
pageFourNew.setProperty(property.getName(),
property.getValue().getString() + "");
jcrSession.save();}
You can easily do this as suggested above at JCR level. But as per CQ practices and this blog
It is better practice to operate at Sling level and NOT JCR level, just to avoid overhead of managing the resources. You can use below code which works:
Resource resource = pageFourNew; // assuming you are getting sling resource properly
ModifiableValueMap valueMap = resource.adaptTo(ModifiableValueMap.class);
for(String key : valueMap.keySet()) {
String value = valueMap.get(key, String.class);
value = value + "additional texts";
valueMap.put(key, value);
}
resource.getResourceResolver().commit();
This is cleaner approach.

Returning composite class with Neo4jClient

The Neop4jClient cypher wiki (https://github.com/Readify/Neo4jClient/wiki/cypher) contains an example of using lambda expressions to return multiple projections...
var query = client
.Cypher
.Start(new { root = client.RootNode })
.Match("root-[:HAS_BOOK]->book-[:PUBLISHED_BY]->publisher")
.Return((book, publisher) => new {
Book = book.As<Book>(),
Publisher = publisher.As<Publisher>(),
});
So the query will return details of both book nodes and publisher nodes. But I want to do something slightly different. I want to combine the contents of a single node type with a property of the matched path. Lets say I have Person nodes with a property 'name', and a class defined so,,,
public class descendant
{
public string name { get; set; }
public int depth { get; set; }
}
A cypher query like this will return what I want, which is all descendants of a given node with the depth of the relationship...
match p=(n:Person)<-[*]-(child:Person)
where n.name='George'
return distinct child.name as name, length(p) as depth
If I try a Neo4jClient query like this...
var query =
_graphClient.Cypher
.Match("p=(n:Person)<-[*]-(child:Person)")
.Where("n.name='George'")
.Return<descendant>("child.name, length(p)") ;
I get an error that the syntax is obsolete, but I can't figure out how should I project the cypher results onto my C# POCO. Any ideas anyone?
The query should look like this:
var query =
_graphClient.Cypher
.Match("p=(n:Person)<-[*]-(child:Person)")
.Where((Person n) => n.name == "George")
.Return((n,p) => new descendant
{
name = n.As<Person>().Name,
depth = p.Length()
});
The Return statement should have the 2 parameters you care about (in this case n and p) and project them via the lambda syntax (=>) to create a new descendant instance.
The main point this differs from the example, is that the example creates a new anonymous type, whereas you want to create a concrete type.
We then use the property initializer (code inside the { } braces) to set the name and depth, using the As<> and Length extension methods to get the values you want.
As a side note, I've also changed the Where clause to use parameters, you should always do this if you can, it will make your queries both faster and safer.

Recursively listing, and storing, directory contents

I know how to recursively list directory contents. I will be using Snow Leopard's enumeratorAtURL:includingPropertiesForKeys:options:errorHandler: method to do this.
However I want to store my findings into a object hierarchy (of, say, objects of a custom FileOrDirectory class that has isLeaf, children, and count attributes).
I need to pre-load the directory and file structure into such a object hierarchy, in order to do whatever I want with NSTreeController and whatnot. I guess the trickiest thing here is to get the children attribute correct in the object hierarchy.
Any ideas?
If I understand your question correctly, you could solve this by writing a recursive function that takes the current node (a file or a folder) and returns an object representing it's structure.
This is Java, but maybe it conveys my idea. I have omitted isLeaf and count, as their values can be derived from the children.
class FileOrFolder
{
String name;
FileOrFolder[] children;
boolean isFile;
}
private FileOrFolder traverse(File file)
{
FileOrFolder fof = new FileOrFolder();
fof.name = file.getAbsolutePath();
if (file.isDirectory())
{
String[] children = file.list();
fof.children = new FileOrFolder[children.length];
for (int i = 0; i < children.length; i++)
{
fof.children[i] = traverse(new File(fof.name + "/" + children[i]));
}
}
fof.isFile = file.isFile();
return fof;
}

ReadAsDataContract exception while reading namespace

I'm trying to consume twitter's REST api mentioned at this link using WCF REST starter kit mentioned at this link.
I'm using the same objects in DataContract as mentioned in the article - statusList and status.
[assembly: ContractNamespace("", ClrNamespace = "TwitterShell")]
[CollectionDataContract(Name = "statuses", ItemName = "status")]
public class statusList : List<status> { }
public class user
{
public string id;
public string name;
public string screen_name;
}
public class status
{
public string id;
public string text;
public user user;
}
I'm reading the XML contents using ReadAsDataContract() method.
HttpClient http = new HttpClient("http://twitter.com/statuses/");
http.TransportSettings.Credentials =
new NetworkCredential("{username}", "{password}");
HttpResponseMessage resp = http.Get("friends_timeline.xml");
resp.EnsureStatusIsSuccessful();
statusList sList = resp.Content.ReadAsDataContract<statusList>();
And I get the following exception. I have not defined the following namespace at all.
Error in line 1 position 24. Expecting element 'statuses' from namespace 'http://schemas.datacontract.org/2004/07/sitename'.. Encountered 'Element' with name 'statuses', namespace ''.
Please help. Thanks.
Just don't do it. You are in for a world of pain if you try using Datacontracts and operation contracts to access non-wcf services.
Ok, so I guess that was a bit unfair leaving you high and dry without an alternative, so try this:
var response = client.Get("http://twitter.com/statuses/friends_timeline.xml");
var statuses = response.Content.ReadAsXElement();
var statusQuery = from st in statuses.Elements("status")
select new status {
id = st.Element("id").Value,
text = st.Element("text").Value,
user = (from us in st.Elements("user")
select new user {
id = us.Element("id").Value,
name = us.Element("name").Value,
screen_name = us.Element("screen_name").Value
}).FirstOrDefault()
};
var statuses = statusQuery.ToList();
Using Linq to XML to create objects from the XML document allows you to avoid the magic of serializers and completely control the names and datatypes of your client side objects. It would be really easy to wrap this as a new HttpContent extension method so that you could simply do:
var statuses = response.Content.ReadAsTwitterStatuses();
I came across your post searching for answers to the same problem and I was able to find a solution for what you are looking for if you want to forgo the LINQ to XML approach.
1) Make sure you annotate your Status class with the following decoration
[DataContract (Namespace = "")]
By specifying the above annotation, you are overriding the namespace from the default namespace of your class. This should fix your namespace problem.
2) To address the issues of nulls (which I also experienced), order of your fields are very important. When your objects are deserialized, it is done in alphabetically order. You can order your fields to match the order of the incoming XML using the Order property on the DataMember annotation.
e.g.
[DataMember (Order = 1)]
public string text
etc ...