уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Казалось бы, такая мелочь — удалить из узла IXMLNode пустой аттрибут xmlns, а нервов потратил :) . Что в принципе нам предоставляет в распоряжение Delphi для работы с XML? Могу перечислить только то, с чем я работал — это модули xmldoc, xmldom, xmlIntf, msxml…вроде бы из стандартных все модули. Можно ещё долго перечислять сторонние компоненты и модули типа simpleXML и т.д., но мне необходимо было реализовать задуманное только с использованием модулей входящих в состав Delphi по умолчанию. А задача была довольно простая — отправить запрос, содержащий определенный XML-документ, на сервер (Googl’у) и создать новый Календарь. То есть, воспользоваться возможностями API Google Celendar.


Формат документа — проще некуда:

<entry xmlns='http://www.w3.org/2005/Atom' 
       xmlns:gd='http://schemas.google.com/g/2005' 
       xmlns:gCal='http://schemas.google.com/gCal/2005'>
  <title type='text'>Little League Schedule</title>
  <summary type='text'>This calendar contains the practice schedule and game times.</summary>
  <gCal:timezone value='America/Los_Angeles'></gCal:timezone>
  <gCal:hidden value='false'></gCal:hidden>
  <gCal:color value='#2952A3'></gCal:color>
  <gd:where rel='' label='' valueString='Oakland'></gd:where>
</entry>

Создать такой документ — дело пяти минут. Единственный момент, который следовало учесть — это объявить пространства имен (xmlns) в корневом узле, иначе Google не принимает такой документ и возникает ошибка.  В своей работе я чаще всего использую для работы с XML интерфейс IXMLDocument. В этот раз решил поступить также. Вот как выглядел код в самом начале:

var ADoc: IXMLDocument;
Root,Node:IXMLNode;
[...]
ADoc:=NewXMLDocument;
ADoc.Active:=true;
Root:=ADoc.AddChild('entry');
for I:=0 to High(clNameSpaces) do //добавляем xmlns
Root.DeclareNamespace(clNameSpaces[i,0],clNameSpaces[i,1]);
 
Node:=Root.AddChild('title'); //добавили узел
Node.Attributes['type']:='text';//добавили аттрибут
Node.Text:='Test Celendar'; //добавили текстовое содержимое
[...]

Аналогичным образом добавлялись и узлы gCal:. В итоге получаяем вот такой документ:

<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gd="http://schemas.google.com/g/2005" xmlns:gCal="http://schemas.google.com/gCal/2005">
 <title xmlns="" type="text">TestCelendar</title>
 <summary xmlns="" type="text">Основной календарь</summary>
 <gCal:timezone value="Asia/Omsk"/>
 <gCal:hidden value="false"/>
 <gCal:color value="#5229A3"/>
 <gd:where valueString="Славный город Омск"/>
</entry>

Обратите внимание на пустые атрибуты xmlns у двух первых узлов. Отправляя такой документ Googl’у получаем ошибку «Добавляемый календарь не имеет названия», т.е. как раз узла title.

Если убираем из корневого элемента:

xmlns="http://www.w3.org/2005/Atom"

То узлы title и summary записываются нормально, но опять же Гугл посылает такой документ в печь. Чтобы кто-то из Вас, уважаемые читатели, не совершал теже самые «танцы с бубном» при работе с XML (всё-таки этот пост я пишу больше для новичков в еле работы с XML) я перечислю то, что делать бесполезно. Итак, при использовании IXMLDocument Вы не избавитесь от пустых атрибутов xmls в узле, если:

1. Попробуете добавить пространства имен после того, как сгенерируете все узлы. Как только вы впишите пространство имен в корневой элемент Вы автоматом получите тот же пустой xmlns=»»;

2. Попробуете удалить атрибут из узла. Этот вариант, на кажущуюся простоту, тоже не проходит. Пример удаления атрибута из узла:

Node:=ADoc.DocumentElement.ChildNodes.FindNode('title');
Node.AttributeNodes.Remove(Node.AttributeNodes['xmlns']);

При выполнении этого кода функция Remove вернет Вам 1, т.е. вроде бы атрибут удален…а документ получим опять «корявый».

3. Не помогли и манипуляции с набором свойств Options у документа.

Если Вы намеревались использоватькакой-то вариант из предложенных выше — не используйте. Всё равно не поможет. Зачаток решения проблемки нагуглился на одном из буржуйских форумах, посвященных работе с MSXML в C++. В Delphi решение проблемы с пустыми xmlns решается следующим образом (на примере того же документа):

ADoc:=NewXMLDocument;
ADoc.Active:=true;
Root:=ADoc.AddChild('entry');
for I:=0 to High(clNameSpaces) do
Root.DeclareNamespace('','http://www.w3.org/2005/Atom');
Node:=ADoc.CreateElement('title','http://www.w3.org/2005/Atom'); //создали узел
Node.Text:='TestCelenda'; //присвоили значение
ADoc.DocumentElement.ChildNodes.Add(Node); //записали документ

Если выполнить этот код получим нормальный правильный XML-документ, без пустых xmlns. Как оказалось, этот вариант работы с узлами является единственно правильным, когда в документе используются пространства имен…Ну что ж, с xmlns  я имел дело впервые и, как говориться «Век живи — век учись». Надеюсь эта заметка поможет кому-нибудь избежать лишних проблем при работе с XML в Delphi.

5 1 голос
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
5 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Семен
Семен
15/06/2010 16:01

Все решения выше приведенные не очень красивые вот нормальный вариант:

NewXMLDocument.GetDocBinding(‘entry’, TXMLentry,’http://www.w3.org/2005/Atom’) as IXMLentry;

в итоге добавится только в entry тег xmlns.

Вадим
Вадим
08/06/2011 06:50

 
А есть ли какой-то компонент, или какой-то способ записи действия пользователя в XML?
Это к вопросу о автоматизации действий. Есть программы для автоматической рассылки объявлений, регистрации в каталогах. Принцип там такой. Пользователь настраивает данные для автоматической регистрации, они заносятся в blob поле в базе данных в виде xml потом когда пользователь нажимает кнопку регистрация, программа считывает оттуда инструкции для каждого сайта свои, и выполняет автоматически действия, как по макросу. Вы знаете, в какую примерно сторону копать, чтобы реализовать нечто подобное?
Спасибо.

Вадим
Вадим
09/06/2011 01:52

  Большое СПСИИБО!!!! Последнее предложение натолкнуло на поисковый запрос: (хранение данных в xml на delphi) и там нашел то, что хотел понять. Зачем так сложно, это просто описал то, что обнаружил изучая готовую аналогичную программу. Данные там действительно заносятся в базу после первой ручной регистрации, но потом уже в следующий раз, когда нужно зарегистрировать другой сайт, иди подать повторно объявление то поля заполняются сами. Можно пройдя руками по 12 доскам запустить поиск однотипных форм, тогда программа просмотрит все ссылки, которые без авто регистрации, и попробует сопоставить имеющиеся на страницах форы с теми, которые уже однажды были заполнены. Под несколько движков… Подробнее »

Vlad
Vlad
09/04/2013 18:28

Спасибо за интересный сайт,
сам мучался с аналогичной проблемой.
Нашел http://www.borlandtalk.com/attribute-xmlns-inherited-from-documentelement-vt99633.html
т.е. в вашем случае должно помочь:
var ADoc: IXMLDocument;
Root,Node:IXMLNode;
[…]
ADoc:=NewXMLDocument;
ADoc.Active:=true;
Root:=ADoc.AddChild(‘entry’, ‘http://www.w3.org/2005/Atom’);