4

I am trying to read the TCM ID from a multi value embedded field using Core Service. I would prefer to avoid using XML and string manipulation as much as possible and thought this was doable using the Fields class I have seen used before (https://github.com/NunoLinhares/TridionWebData/blob/master/ImportContentFromRss/ImportContentFromRss/Content/Fields.cs)

My main schema (Item Container) has a multi valued field called "items" which takes an embedded schema. The embedded schema has 2 fields: accountUrl (which takes a string) and icon (which is a ComponentLinkField). I want to find all components using Item Container and then in a loop get the TCM ID of the linked "icon" component. I will then Read the component from that TCM and check what Schema it is using. The issue is that when I run over my loop it will get only the first occurrence of "items" and will get the "icon" field TCM but then the loop will exit and it will grab the next component even if there are multiple "items" in the first Item Container.

// TCM ID of the main schema who's field we want to check
// Ex tcm: 8-44-8 is Item Container
string mainComponentSchemaTcm = "tcm:8-44-8";

// XML name of the schema field we want to check
string checkComponentField = "icon";

// Schema of the linked component we want to know if it is used in checkComponentField
string linkedComponentSchema = "Image";

// Are we checking embedded fields?
bool checkEmbeddedFields = true;

// If we are checking embedded fields what is the parent field/attribute holding the embedded field(s)
string parentField = "items";

// Creating the core service.
// Using "wsHttp_2013" binding to create the client, Other bindings (like "netTcp_2013") could be used depending on the need.
SessionAwareCoreServiceClient client = new SessionAwareCoreServiceClient("wsHttp_2013");

// Set up our search query filter to look only for components
SearchQueryData filter = new SearchQueryData();
filter.ItemTypes = new ItemType[] { ItemType.Component };

// In our case we only want components using a specific schema so we use it's TCM ID
// We use BasedOnSchemaData to get all the schema information and then set the filter above
// to use this specific schema
BasedOnSchemaData mainSchema = new BasedOnSchemaData();
mainSchema.Schema = new LinkToSchemaData() { IdRef = mainComponentSchemaTcm };
filter.BasedOnSchemas = new BasedOnSchemaData[] { mainSchema };

// Get the schema fields of our main schema using mainComponentSchemaTcm.
// Ex tcm: 8-44-8 is Item Container which contains the field "items"
// we also need to set whether we are checking and expanding embedded fields.
// For our Item Container "items" uses embedded fields "AccountURL" and "icon"
SchemaFieldsData schemaFields = client.ReadSchemaFields(mainComponentSchemaTcm, checkEmbeddedFields, new ReadOptions());

// Get list of components using our filter
var componentSearchResults = client.GetSearchResults(filter);

// We want to check each component in our results
foreach (var component in componentSearchResults)
{
    var currentItem = (ComponentData)component;

    // currentItem does not contain complete data for current component so we need to read the full data with client.Read
    ComponentData compReadData = (ComponentData)client.Read(currentItem.Id, new ReadOptions());

    // get content of component/schema fields for current component
    var fieldsContent = Fields.ForContentOf(schemaFields, compReadData);
    string tcmOfIcon = "";

    foreach (var field in fieldsContent)
    {
        if (!string.IsNullOrEmpty(field.Value))
        {
            tcmOfIcon = field[checkComponentField].Value;
        }
    }
}

This code is incomplete but the main issue is the foreach (var field in fieldsContent) will only execute one time per component. Is this possible to do the way I'm trying or is the only way to parse through the XML?

Thanks for looking!

4

The key here is that, while for regular fields, the Value (or Values) property will give you the value of the field, but for embedded schema fields, you should use the SubFields property. This will give you one or more field objects containing the fields inside the embedded schema.

Your code would become something like this (it could use some extra null-checking but I omitted that for clarity)

foreach (var component in componentSearchResults)
{
    var currentItem = (ComponentData)component;

    // currentItem does not contain complete data for current component so we need to read the full data with client.Read
    ComponentData compReadData = (ComponentData)client.Read(currentItem.Id, new ReadOptions());

    // get content of component/schema fields for current component
    var fieldsContent = Fields.ForContentOf(schemaFields, compReadData);
    string tcmOfIcon = "";

    foreach (var embeddedField in fieldsContent["name_of_embedded_field"].SubFields)
    {
        tcmOfIcon = embeddedField["name_of_icon_field"].Value;
        //do something with this tcm uri and move on to the next
    }
}
1

I think its easier to get the XML nodes and trace the content...

foreach (XElement element in client.GetListXml(currentItem.Id, yourFilterData).Nodes())
                { 
                    var itemXML = element.ToString(); //to inspect the content
                    var itemTitle = element.Attribute("Title").Value;
                    var itemType = element.Attribute("Type").Value.ToString();
                    var itemID =  element.Attribute("ID").Value.ToString();  
                    ...                

                }
  • 1
    It might be the easier method overall but I specifically wanted to do it without simply parsing strings or XML. I haven't done a whole lot of work with the Core Service and while I'm learning it I want to learn more about what it can do and what I have access to. Thanks for your answer though, that should do what I need. – G. Robb Jan 25 '17 at 15:59

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.