dicomdcmtk

Getting the tag path of a particular DcmElement


I am using dcmtk to retrieve the list of all DCM_CodeMeaning contained in a DcmDataset:

DcmDataset* dataset = file_format.getDataset();
DcmStack result_stack;
const OFCondition condition =
    dataset->findAndGetElements(DCM_CodeMeaning, result_stack);

What I fail to understand is from this result_stack how to I get the tag-path associated with each matching DcmElement ?

The parent item (element->getParentItem()) of this DcmElement is exactly the DcmItem I was expecting, but I cannot get the DcmTag of the DcmSequenceOfItems containing that particular DcmItem.

I tried to get the parent item item->getParentItem() but this returns directly the complete dataset parentItem->ident() == EVR_dataset.

My goal is to construct a tag-path (eg. "(0008,1032)[0].(0008,0104)") to describe the location of each matching DcmElement(s).


Solution

  • The short answer is: Instead of getParentItem() you should call getParent() on the item in order to get the SQ element that contains this item, because a DcmSequenceOfItems is not a DcmItem. However, DcmDataset is derived from DcmItem, that's why you get the top-level DICOM data set when you call getParentItem() on an item of a top-level SQ element. All this information should also be available from the API documentation (if not, please let me know and I'll improve it).

    In principle, the DcmPathProcessor could do what you want, but it is currently rather limited in terms of functionality and only supports the other direction, i.e. finds an item or element (or even multiple) from a given path.


    There is no API to directly retrieve the index of an item within a DcmSequenceOfItems, but you can use DcmSequenceOfItems::getItem to compute it. For example:

    std::string getTagPath(DcmElement* element) {
      if (!element) {
        throw std::invalid_argument("Input DcmElement is null");
      }
    
      DcmObject* current = element;
      std::string result = current->getTag().toString();
      while (current) {
        DcmObject* parent = current->getParent();
        if (parent) {
          if (parent->ident() == EVR_SQ) {
            DcmSequenceOfItems* sequence = OFdynamic_cast(DcmSequenceOfItems*, parent);
            // Find the index of the current item in the sequence
            DcmItem* currentItem = OFdynamic_cast(DcmItem*, current);
            if (currentItem) {
              std::ostringstream itemIndex;
              for (unsigned long i = 0; i < sequence->card(); ++i) {
                if (sequence->getItem(i) == currentItem) {
                  itemIndex << "[" << i << "]";
                  break;
                }
              }
              result.insert(0, parent->getTag().toString() + itemIndex.str());
            }
          } else if (parent->ident() == EVR_item) {
            result.insert(0, ".");
          }
        }
        current = parent;
      }
      return result;
    }