Hi,

I want to inform you that I currently put the aside the intention of
adding xmlDOMWrapSetAttr(Node) and xmlDOMWrapRemoveAttr(Node)
functionality. Looking at the code of the Delphi-wrapper, I'm having
difficulties in finding oppropriate code to be put into Libxml2,
which does what I need without adding a lot of additional stuff.

However, I still would be happy if there would be more Libxml2
code, which would be intended to be used by DOM(-like)
wrappers, in order to avoid inventing the wheel for every wrapper
out there.

I attached a snippet of the Delphi-wrapper's internal
set-attribute-ns code for anyone who's interested in the
issue; this is how I tried to solve it in Delphi. This currently
avoids any IDness semantics.

Regards,

Kasimier




procedure ozdom_setAttributeValue(const aDoc: IDOMDocument;
  const aElement: IDOMElement; const aAttr: IDOMAttr; aLxAttr: xmlAttrPtr; 
const aValue: DOMString);

  procedure _RaiseAlreadyExists;
  begin
    raise EDOMException.create(NOT_SUPPORTED_ERR,
      'Cannot change the nodeValue of a default attribute if it already exists 
as a specific attribute.',
      nil, 'ozdom_setAttributeValue');
  end;

  procedure _SetValueDefault;
  // The messy DTD-default-attribute stuff.
  var
    lxNs: xmlNsPtr;
    lxAttrDecl: xmlAttributePtr;
    lxElem: xmlNodePtr;
  begin
    // Clone the attribute declaration into a normal attribute and add it to 
its owner element.
    // Problematic scenario:
    //   The default attribute is hold by two wrappers.
    //   The first one changes the nodeValue -> a normal attribute is created.
    //   The second one changes the nodeValue -> again, a normal attribute is 
created.
    //   This will result is two attributes with the same name being created.
    // We'll solve this by looking up if an equal "normal" attribute already 
exists;
    //   a bit messy though.
    lxElem := (aElement as IDOMLxNodeAccess).getLxNodePtr();
    lxAttrDecl := xmlAttributePtr(aLxAttr);
    // Do not allow changes to fixed attributes.
    if (lxAttrDecl.def = XML_ATTRIBUTE_FIXED) then
      raise EDOMException.Create(NO_MODIFICATION_ALLOWED_ERR,
        'Cannot change the value of a FIXED attribute.',
        nil, 'ozdom_setAttributeValue');

    // Process only, if the default attribute is not already existent as a 
namespace declaration
    // attribute (nsDef entry). IOW, do not allow changes to namespace 
declaration attributes.
    if // @attrDecl.prefix is "xmlns" if it declares a prefixed namespace.
      ((lxAttrDecl.prefix <> nil) and
       (xmlStrEqual(lxAttrDecl.prefix, xmlCharPtr('xmlns')) = 1)) or
      // @attrDecl.name is "xmlns" if it declares a default namespace.
      (xmlStrEqual(lxAttrDecl.name, xmlCharPtr('xmlns')) = 1)
    then begin
      raise EDOMException.Create(NO_MODIFICATION_ALLOWED_ERR,
        'Changing of default (from a DTD) namespace declaration attributes is 
not supported (yet).',
        nil, 'ozdom_setAttributeValue');
      // TODO -oKB: Support changing of default ns-decl attributes.
    end;
    // Process only, if the default attribute was not already converted to a 
"normal" attribute.
    // This is needed for the scenario where the default attribute is hold by 
multiple wrappers.
    if (ozdom_getNormalAttribute(lxElem, lxAttrDecl.prefix, lxAttrDecl.name) <> 
nil) then
      // EXCEPTION.
      _RaiseAlreadyExists;

    // Copy the namespace.
    // Because an attribute declaration carries only the prefix with it, we 
have to lookup its
    // namespace.
    if (lxAttrDecl.prefix <> nil) then begin
      // TODO 1 -oKB: We need a *strict* ns-lookup-by-prefix function in 
Libxml2.
      if (ozdom_searchNsByPrefixStrict(lxElem.doc, lxElem, lxAttrDecl.prefix, 
lxNs) <> 1) then
        raise EDOMException.Create(NAMESPACE_ERR,
          Format('No namespace declaration in scope for the prefix "%s".', 
[UTF8Decode(lxAttrDecl.prefix)]),
          nil, 'ozdom_setAttributeValue');
    end else
      lxNs := nil;

    // Clone the default attr; i.e. create a "specified" attribute.
    // Don't clone the value, since we are going to change it afterwards anyway.
    aLxAttr := ozdom_cloneAttrDecl(lxAttrDecl, aDoc, false, lxNs);
    if (aLxAttr = nil) then
      raise EDOMException.Create(NAMESPACE_ERR,
        'Failed to clone a default attribute.',
        nil, 'ozdom_setAttributeValue');

    // The attr-wrapper will be re-initialized with a clone of the attribute 
declaration.
    if (aAttr <> nil) then
      (aAttr as IInternalDOMNode).initInternalStructure(xmlNodePtr(aLxAttr));

    // Append it to the element's attributes.
    ozdom_appendAttributeRaw(lxElem, aLxAttr);

    // Set the value.
    if (aValue <> '') then
      xmlAddChild(xmlNodePtr(aLxAttr), xmlNewDocText(lxElem.doc, 
xmlCharPtr(UTF8Encode(aValue))));
  end;

  procedure _RemoveContent;
  var
    cur, tmp: xmlNodePtr;
  begin
    // Don't free the nodes, since they might be referenced by wrappers.
    // xmlFreeNodeList(aLxAttr.children);
    // TODO -oKB: This is not very efficient, but how to do it otherwise?
    cur := aLxAttr.children;
    while (cur <> nil) do begin
      tmp := cur;
      cur := cur.next;
      tmp.next := nil;
      tmp.prev := nil;
      tmp.parent := nil;
      (aDoc as IInternalDOMDocument).addOrphanNode(xmlNodePtr(tmp));
    end;
    aLxAttr.children := nil;
    aLxAttr.last := nil;
  end;

begin
  if (aLxAttr.type_ = XML_ATTRIBUTE_DECL) then begin
    _SetValueDefault();
  end else begin
    if (aLxAttr.children <> nil) then begin
      _RemoveContent();
    end;
    // Set the value.
    if (aValue <> '') then
      xmlAddChild(xmlNodePtr(aLxAttr), xmlNewDocText(aLxAttr.doc, 
xmlCharPtr(UTF8Encode(aValue))));
  end;
end;

procedure TDOMElement.internalSetAttributeNS(const aNamespaceURI, aPrefix, 
aLocalName, aValue: DOMString);
var
  lxPrefix, lxNamespaceURI, lxLocalName: xmlCharPtr;
  lxAttr: xmlAttrPtr;
begin
  lxLocalName := xmlCharPtr(UTF8Encode(aLocalName));

  if (aPrefix = '') then
    lxPrefix := nil
  else
    lxPrefix := xmlCharPtr(UTF8Encode(aPrefix));

  if (aNamespaceURI = '') then
    lxNamespaceURI := nil
  else
    lxNamespaceURI := xmlCharPtr(UTF8Encode(aNamespaceURI));

  // xmlHasNSProp() will also return default/fixed attribute declarations of a 
DTD.    
  lxAttr := xmlHasNsProp(fXmlNode, lxLocalName, lxNamespaceURI);

  // Do not modify fixed attributes.
  if (lxAttr <> nil) then
    check_fixedAttr(lxAttr);
    
  // Create a new attribute-node if needed.
  if (lxAttr = nil) then begin
    lxAttr := xmlNewDocProp(fXmlNode.doc, lxLocalName, nil);
    if (lxAttr = nil) then
      raise EDOMException.Create(0, 'Internal Libxml2 error: xmlNewDocProp() 
failed.',
        self, 'internalSetAttributeNS');
    // Aquire the namespace structure.
    if (lxNamespaceURI <> nil) then begin
      lxAttr.ns := (fOwnerDocument as 
IInternalDOMDocument).acquireNs(lxNamespaceURI, lxPrefix);
      if (lxAttr.ns = nil) then
        raise EDOMException.Create(0, 'Failed to acquire a namespace 
structure.',
          self, 'internalSetAttributeNS');
    end;
    // Append it to the element's attributes.
    ozdom_appendAttributeRaw(fXmlNode, lxAttr);
  end;

  // Set the attribute's value.
  ozdom_setAttributeValue(fOwnerDocument, self, nil, lxAttr, aValue);
  (fOwnerDocument as IInternalDOMDocument).switchOnChanged;
end;

procedure TDOMElement.internalSetNSDeclarationAttribute(const aPrefix, 
aNamespaceURI: DOMString);
var
  lxNs: xmlNsPtr;
begin
  lxNs := ozdom_getDeclaredNamespaceByPrefix(fXmlNode, aPrefix);
  if (lxNs = nil) then begin
    // Create a new namespace declaration attribute.
    // This puts the ns into the nsDef list.
    lxNs := ozdom_CreateNsDeclAttr(fXmlNode, aNamespaceURI, aPrefix);
    (fOwnerDocument as IInternalDOMDocument).switchOnChanged;
  end else begin
    // TODO -oKB: We do not yet support changing of the value of a namespace 
declaration attribute.
    //   Remove it and add a new one as a workaround.
    if (strComp(lxNs.href, xmlCharPtr(UTF8Encode(aNamespaceURI))) <> 0) then
      raise EDOMException.Create(NO_MODIFICATION_ALLOWED_ERR, 'Cannot change 
the value of a ' +
        'namespace declaration attribute.', self, 'setAttribute');
  end;
end;
_______________________________________________
xml mailing list, project page  http://xmlsoft.org/
[email protected]
http://mail.gnome.org/mailman/listinfo/xml

Reply via email to