Re-use "CreateSegment" function to process content of a tagpair

Dear Community members,

I am developing a bilingual file type. In the Sample BIL parser, the "CreateSegment" function is implemented as follows:

private ISegment CreateSegment(XmlNode seg, ISegmentPairProperties pair)

{

ISegment segment = ItemFactory.CreateSegment(pair);

foreach (XmlNode item in seg.ChildNodes)

{

if (item.NodeType == XmlNodeType.Text)

{

segment.Add(CreateText(item.InnerText));

}

if (item.NodeType == XmlNodeType.Element)

{

segment.Add(CreateTagPair(item));

}

}

return segment;

}

 

How should I proceed if I want to re-use this same function in the CreateTagPair function, if I detect that the tagpair contains further tags for example.

Currently, I just copied/pasted the code but this is not nice and I would prefer if I could use the same function for both calls. Should I use a IMarkupDataContainer? If yes, how should I declare it? How can I convert it back to ISegment or insert it in my tagpair?

Thanks in advance for your support.

Regards,

Laurent

  • Hi Laurent,

    Code is untested, but I think you can take advantage of the fact that ISegment and ITagPair both inherit from IAbstractMarkupDataContainer and use recursion.

    private void RecurseNodes(XmlNodeList nodeList, IAbstractMarkupDataContainer container)
    {
        foreach (XmlNode item in nodeList)
        {
            if (item.NodeType == XmlNodeType.Text)
            {
                     // If it is text, just add to the container and you are done
                container.Add(CreateText(item.InnerText));
            }

            if (item.NodeType == XmlNodeType.Element)
            {
                var tagPair = CreateTagPair(item);
                      // Add the tag pair to its parent container
                container.Add(tagPair);
                // Recurse to add all children to the tagpair
                RecurseNodes(item.ChildNodes, tagPair);
            }

        }
    }

    Then in CreateSegment, call it like the following:

    private ISegment CreateSegment(XmlNode segNode, ISegmentPairProperties pair)
    {
        ISegment segment = ItemFactory.CreateSegment(pair);
        // Collect all the children and add them to the ISegment
        RecurseNodes(segNode.ChildNodes, segment);

        return segment;
    }

    And in CreateTagPair, remove the call to tagPair.Add(CreateText(item.InnerText)); since you will add it in RecurseNodes.

  • Hi Jesse,

    Thank you for your reply.

    My idea was also to use IAbstractMarkupDataContainer and to implement it has you suggested. However, I am still facing an issue: how should I re-use the result of the RecurseNodes function? I envisaging one of the following options:

    1. RecurseNodes as a void method (as in your example): in this case, the IAbstractMarkupDataContainer parameter should be passed as ref or out parameter. However, I can only do this if the segment/tag pair is converted to IAbstractMarkupDataContainer. And this where I am stuck: how do I convert from e.g. ISegment to IAbstractMarkupDataContainer and back after the call?

    2. The RecurseNodes returns the passed IAbstractMarkupDataContainer. In this case, I can call the method by passing the ISegment/ITagPair directly. in this case, to which property should I re-assign the returned IAbstractMarkupDataContainer ?

    Thanks in advance for your help.

    Regards,
    Laurent
  • Hi Laurent,

    >the IAbstractMarkupDataContainer parameter should be passed as ref or out parameter
    I'm not sure why you need ref or out? In my example, all you are doing is "Add"ing to the container.

    2. I'm not 100% clear on the question, but where you thinking something like this (sorry untested code)?

    private IAbstractMarkupDataContainer RecurseNodes(XmlNodeList nodeList, IAbstractMarkupDataContainer container)
    {
        foreach (XmlNode item in nodeList)
        {
            if (item.NodeType == XmlNodeType.Text)
            {
                container.Add(CreateText(item.InnerText));
            }

            if (item.NodeType == XmlNodeType.Element)
            {
                var tagPair = RecurseNodes(item.ChildNodes, CreateTagPair(item));
                container.Add((IAbstractMarkupData)tagPair);
            }
        }

        return container;
    }

  • Dear Jesse,

    Thank you for your prompt reaction and sorry for my late reply.

    Concerning 1, I wanted to pass the parameter as ref or out because it needs to be changed. Or do you mean I should declare the container as constant?

    Concerning 2, yes, I meant to return it the way you mentioned. However, to which property of the segment / tag pair should I assign the returned value? Or can I just cast the container to a segment/tag pair?

    Regards,

    Laurent
  • Hi Laurent,

    For 1, I think I might need to see code for what you are trying to do.
    Now answering your original question, casting ISegment to IAbstractMarkupDataContainer and back should work fine!

    >Or can I just cast the container to a segment/tag pair?
    Yes, casting should work fine as long as the object is an instance of the type your are casting too.

    Sorry, I couldn't help more, but if you have example code, I might be able to understand better!

    Hope that helps,
    Jesse