anchor.diff:    end;
   end;
   
  +function TXmlNode.NodeByAttributeValue(const NodeName, AttribName, AttribValue: array of Utf8String;
  +  ShouldRecurse: boolean = True): TXmlNode;
  +var
  +  i,j: integer;
  +  Node: TXmlNode;
  +begin
  +  Result := nil;
  +  // Find all nodes that are potential results
  +  for i := 0 to NodeCount - 1 do
  +  begin
  +    Node := Nodes[i];
  +    for j:= Low(NodeName) to High(NodeName) do
  +    if (UTF8CompareText(Node.Name, NodeName[j]) = 0) and
  +        Node.HasAttribute(AttribName[j]) and
  +       (UTF8CompareText(Node.AttributeValueByName[AttribName[j]], AttribValue[j]) = 0) then
  +    begin
  +      Result := Node;
  +      exit;
  +    end;
  +    // Recursive call
  +    if ShouldRecurse then
  +      Result := Node.NodeByAttributeValue(NodeName, AttribName, AttribValue, True);
  +    if assigned(Result) then
  +      exit;
  +  end;
  +end;
  +
   function TXmlNode.HasAttribute(const AName: Utf8String): boolean;
   var
     i: integer;
  
positive.code:         SubNode.WriteStream(S);
  
        if HasSubElements and (SubNode is TsdCharData) then
          sdStreamWriteString(S, GetEndOfLine);
      end;
  
      // endtag
  
negative.code:     // function, this function will search the whole subnode tree. If you use
      // a TsdNodeList for the AList parameter, you don't need to cast the list
      // items to TXmlNode.
      procedure FindNodes(const NodeName: Utf8String; const AList: TList); overload; virtual;
      procedure FindNodes(const NodeName: array of Utf8String; const AList: TList); overload; virtual;
      // Iterates the next sibling of Node
      function NextSibling(ANode: TXmlNode): TXmlNode; virtual;
      // Return the first subnode with AType, or nil if none
  