10

I'm trying to retrieve a hierarchy of categories/keywords from the Core Service on Tridion 2013.

I want to either retrieve the whole tree in one request, i.e. pass in a Category ID and get its child keywords, and their child keywords and so forth;

Or be able to retrieve individual levels of the tree, i.e. pass in a Category ID and get its immediate child keywords. And then be able to pass in one of the child Keyword IDs and retrieve its immediate children.

I've tried using the following code:

var items = _client.GetList(categoryId, new KeywordsFilterData());

And:

var items = _client.GetList(keywordId, new ChildKeywordsFilterData());

But both methods simply return the whole tree as a flattened list. This wouldn't be a problem if the KeywordData.ParentKeywords property wasn't always null on the returned items, as I could parse the results and build the tree myself.

It must be possible to do this, as the CME loads its tree one level at a time, and I was under the impression that in Tridion 2013 everything (except legacy backwards compatibility) uses the Core Service.

I'm currently stumped by this, so any help anyone can give would be much appreciated.

EDIT

Thanks for your help guys, I've ended up using the TaxonomiesOwlFilterData option and parsing the XML, as I can get the whole tree in one hit, parse it and any keyword metadata and cache it for later use.

Here's my solution, with some bits snipped for brevity:

public CategoryItem GetHierarchy(string categoryId)
{
    var tcmUri = new TcmUri(categoryId);
    var filter = new TaxonomiesOwlFilterData
    {
        RootCategories = new[] {new LinkToCategoryData {IdRef = categoryId}}
    };

    var publicationId = "tcm:0-{0}-1".FormatWIth(tcmUri.PublicationId);

    var xml = _client.GetListXml(publicationId, filter);

    return Parse(publicationId, categoryId, xml);
}

public CategoryItem Parse(string publicationId, string categoryId, XElement xml)
{
    XNamespace rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
    XNamespace rdfs = "http://www.w3.org/2000/01/rdf-schema#";
    XNamespace tcmt = "http://www.tridion.com/ContentManager/5.2/Taxonomies#";
    XNamespace tcmc = publicationId + "/Categories#";

    var category = xml.Element(tcmt + "Taxonomy");

    var result = new CategoryItem
    {
        Id = category.Attribute(rdf + "about").Value,
        Title = category.Element(rdfs + "label").Value
    };

    foreach (var rootKeyword in category.Elements(tcmt + "rootKeyword"))
    {
        var id = rootKeyword.Attribute(rdf + "resource").Value;
        var element = xml.Elements().First(e => e.Attribute(rdf + "about").Value == id);
        var title = element.Element(rdfs + "label").Value;

        var keyword = new KeywordItem {Id = id, Title = title};

        ParseChildren(keyword, xml, element);

        result.Keywords.Add(keyword);
    }

    return result;
}

public void ParseChildren(KeywordItem parent, XElement xml, XElement parentElement)
{
    XNamespace rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
    XNamespace rdfs = "http://www.w3.org/2000/01/rdf-schema#";
    XNamespace tcmt = "http://www.tridion.com/ContentManager/5.2/Taxonomies#";

    foreach (var childKeyword in parentElement.Elements(tcmt + "childKeyword")) 
    {
        var id = childKeyword.Attribute(rdf + "resource").Value;
        var element = xml.Elements().First(e => e.Attribute(rdf + "about").Value == id);
        var title = element.Element(rdfs + "label").Value;

        var keyword = new KeywordItem {Id = id, Title = title};

        ParseChildren(keyword, xml, element);

        parent.Children.Add(keyword);
    }
}
  • What is your requirement for getting this list exactly, what will you be using it for? Depending on that the answer might vary. – Bart Koopman Aug 20 '13 at 9:20
  • @BartKoopman its being used to generate some search filters in another application which are then used against a Solr index. The filters have been specced as multi-leveled - so the user can drill down. – James Simm Aug 20 '13 at 9:28
  • if that Solr index is part of the Presentation Server, then you might want to consider the Broker API for Taxonomies (and publish your Taxonomy) – Bart Koopman Aug 20 '13 at 10:10
  • Regrading "Tridion 2013 everything (except legacy backwards compatibility) uses the Core Service" -- I understand this to be true as well, but specifically for the Content Manager Explorer interacting with the CMS. This excludes things like the publisher updating published status and other "external" systems. – Alvin Reyes Aug 20 '13 at 19:18
10

As Will recalls in his answer, you can try the TaxonomiesOwlFilterData. Here a sample

TaxonomiesOwlFilterData filter = new TaxonomiesOwlFilterData();
filter.RootCategories = new LinkToCategoryData[] { new LinkToCategoryData() { IdRef = "[CategoryId]" } };

XElement result = channel.GetListXml("[PublicationId]", filter);

It will return you data in the format of

<tcmc:[CategoryName] rdf:about="[ChildKeywordId]">
    <rdfs:label>[ChildKeywordTitle]</rdfs:label>
    <rdfs:comment>[ChildKeywordDesc]</rdfs:comment>
    <tcmt:key></tcmt:key>
    <tcmt:isAbstract>true</tcmt:isAbstract>
    <tcmt:isRoot>true</tcmt:isRoot>
    <tcmt:metadata rdf:parseType="Literal" />
    <tcmt:childKeyword rdf:resource="[Inner Keyword Id]" />
    <tcmt:childKeyword rdf:resource="[Inner Keyword Id]" />
    <tcmt:childKeyword rdf:resource="[Inner Keyword Id]" />
</tcmc:[CategoryName]>
8

To get a list of Keywords from a Category using the Core Service, you can indeed use the GetList (or GetListXml) method and supply a KeywordsFilterData.

That will by default return you all (child) Keywords, without a hierarchy, if you want the hierarchy, you will have to set the IsRoot property in the KeywordsFilterData to true:

var items = _client.GetList(categoryId, new KeywordsFilterData() { IsRoot = true });

Your following requests can then be on a specific Keyword, requesting its children:

var items = _client.GetList(keywordId, new ChildKeywordsFilterData());

This is exactly how I build up the treeview in the ItemSelector Custom URL extension, you can see it on lines 117 to 124 of the TridionTreeView custom control.

  • Hi Bart , i need help to get Catogory and it's children, how do i achieve this in java? , because when i call getList() method i get exception com.sdltridion.contentmanager.coreservice.ICoreServiceGetListXmlCoreServiceFaultFaultFaultMessage: Unexpected item type: Category. – Neetesh Narvaria Oct 18 '16 at 6:11
  • @NeeteshNarvaria same as you do it in .NET, by using the API, check out the API documentation, to ensure you are using the correct method calls – Bart Koopman Oct 18 '16 at 9:02
7

The TOM.NET contains the Repository.GetTaxonomiesOwl() method which can be used to get the whole taxonomy with relationship information, however I do not see an equivalent in the Core Service API. There is a TaxonomiesOwlFilterData filter class in the Core Service API, however it does state that this cannot be used with GetList(), so probably you would have to use this with GetListXml() - and I have no idea if this will give you what you want as I have not tried it -but give it a go and let us know...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.