Search code examples
xmldelphiomnixml

how to process a xml node text up to the first subnode and after the last one?


<p> Normal text <b> bolded </b> finish normal text </p>

Im processing that xml (example reduced) with OmniXML (but I believe the solution will apply to other XML parsers). Im traversing the xml and everytime I process a p or b tag I change some font settings etc.

The problem is that when I have a Node var pointing to the p tag and I do

Node.TextNode

it returns "Normal text bolded finish normal text" the complete text, but I want to return only the part up to the first tag (and also latter the last part); This way when y process the tag thereafter I can change the font settings, and print the bolded text..

How I can do that?


Solution

  • uses
      OmniXML,
      OmniXMLUtils;
    
    procedure ProcessNode(const node: IXMLNode; nodeText: TStrings);
    
      procedure CollectNodes(const node: IXMLNode; const nodeList: IXMLNodeList);
      var
        childNode: IXMLNode;
        iChild   : integer;
      begin
        for iChild := 0 to node.ChildNodes.Length-1 do begin
          childNode := node.ChildNodes.Item[iChild];
          if childNode.NodeType = TEXT_NODE then
            nodeText.Add(childNode.NodeValue)
          else if childNode.NodeType = ELEMENT_NODE then begin
            nodeText.Add(childNode.NodeName);
            CollectNodes(childNode, nodeList);
            nodeText.Add('/' + childNode.NodeName);
          end;
        end;
      end; { CollectNodes }
    
    var
      childNode: IXMLNode;
      nodeList : IXMLNodeList;
    begin
      nodeList := TXMLNodeList.Create;
      CollectNodes(node, nodeList);
    end; { ProcessNode }
    
    procedure TForm39.FormCreate(Sender: TObject);
    var
      xml: IXMLDocument;
      nodeText: TStringList;
    begin
      xml := CreateXMLDoc;
      if XMLLoadFromString(xml, '<test><p> Normal text <b> bolded </b> finish normal text </p></test>') then begin
        nodeText := TStringList.Create;
        try
          ProcessNode(xml.SelectSingleNode('test'), nodeText);
        finally FreeAndNil(nodeText); end;
      end;
    end;
    

    Will give you:

    p
     Normal text
    b
     bolded
    /b
     finish normal text
    /p