简体   繁体   中英

How to properly create XML header (to fill pdf documents in xfdf format) with Delphi using IXMLDOCUMENT

please I need help to achieve this xml, I have a problme with the third line, this is what I get with my code:

<?xml version="1.0" encoding="utf-8"?>
<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">
  <f xmlns="" href="myExample.pdf">
    <fields>
      <field name="chk01">
        <value>X</value>
      </field>
      <field name="chk02">
        <value>X</value>
      </field>
      <field name="edt11">
        <value>Some text</value>
      </field>
    </fields>
  </f>
</xfdf>

and this is what I need:

<?xml version="1.0" encoding="UTF-8"?>
<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">    
  <f href="myExample.pdf"/>
  <fields>
    <field name="chk01">
      <value>X</value>
    </field>
    <field name="chk02">
      <value>X</value>
    </field>
    <field name="edt11">
      <value>Some text</value>
    </field>
  </fields>
</xfdf>

I dont know how to create the "f" tag like in the second example, notice that it's a little bit different and it closes in the same line and not before the last line like in the first example.

Here is my code:

....
Var
  XML : IXMLDOCUMENT;
  RootNode, NodeLevel1, CurNode : IXMLNODE;
Begin
  XML := NewXMLDocument;
  XML.Encoding := 'utf-8';
  XML.Options := [doNodeAutoIndent];

  RootNode := XML.AddChild('xfdf');
  RootNode.Attributes['xmlns']:= 'http://ns.adobe.com/xfdf/';
  RootNode.Attributes['xml:space']:= 'preserve';

  RootNode := XML.DocumentElement.AddChild('f');
  RootNode.Attributes['href']:= 'myExample.pdf';

  NodeLevel1 := RootNode.AddChild('fields');
  CurNode := NodeLevel1.AddChild('field');
  CurNode.Attributes['name'] := 'chk01';
  CurNode := CurNode.AddChild('value');
  CurNode.Text:= 'X';

  CurNode := NodeLevel1.AddChild('field');
  CurNode.Attributes['name'] := 'chk02';
  CurNode := CurNode.AddChild('value');
  CurNode.Text:= 'X';

  CurNode := NodeLevel1.AddChild('field');
  CurNode.Attributes['name'] := 'edt11';
  CurNode := CurNode.AddChild('value');
  CurNode.Text:= 'Some text';

 XMl.SaveToFile('C:\New.fdf');

you mixed node

f is child xfdf

filds is also child xfdf

solution

Var
XML : IXMLDOCUMENT;
fnode, RootNode, NodeLevel1, CurNode : IXMLNODE;
Begin
XML := NewXMLDocument;
XML.Encoding := 'utf-8';
XML.Options := [doNodeAutoIndent];

RootNode := XML.AddChild('xfdf');
RootNode.Attributes['xmlns']:= 'http://ns.adobe.com/xfdf/';
RootNode.Attributes['xml:space']:= 'preserve';

fnode := RootNode.AddChild('f');
fNode.Attributes['href']:= 'myExample.pdf';

NodeLevel1 := RootNode.AddChild('fields');
CurNode := NodeLevel1.AddChild('field');
CurNode.Attributes['name'] := 'chk01';
CurNode := CurNode.AddChild('value');
CurNode.Text:= 'X';

CurNode := NodeLevel1.AddChild('field');
CurNode.Attributes['name'] := 'chk02';
CurNode := CurNode.AddChild('value');
CurNode.Text:= 'X';

CurNode := NodeLevel1.AddChild('field');
CurNode.Attributes['name'] := 'edt11';
CurNode := CurNode.AddChild('value');
CurNode.Text:= 'Some text';

XMl.SaveToFile('C:\tmp\New.fdf');end;

You are getting a bad result because:

  1. you are not handling XML namespaces correctly.

  2. you are creating the fields node as a child of the f node instead of as a child of the xfdf node.

When a child node is added, it inherits its parent node's namespace unless you explicitly specify a different namespace, and the namespace cannot be changed once assigned.

In your case, your xfdf node is not actually being added to the Adobe namespace, you are faking it! The XML engine does not know about the namespace, so the xfdf node has a blank namespace, which the f child node inherits. That is why the f node ends up with the unwanted xmlns="" attribute, so there is no ambiguity as it which namespace child nodes belong to.

To declare a namespace correctly so the XML engine knows about it, you need to use the IXMLNode.DeclareNamespace() method instead of using the IXMLNode.Attributes property.

You can either:

  1. explicitly declare the Adobe namespace on the xfdf node after adding it to the document. The xfdf node itself will not be in the namespace (as evident by the IXMLNode.NamespaceURI property still being blank), but the namespace can then be explicitly applied when adding the f and fields child nodes:

     const NsAdobeXfdf = 'http://ns.adobe.com/xfdf/'; var XML: IXMLDocument; RootNode, FNode, FieldsNode, FieldNode: IXMLNode; begin XML := NewXMLDocument; XML.Encoding := 'utf-8'; XML.Options := [doNodeAutoIndent]; RootNode := XML.AddChild('xfdf'); // <-- xfdf is not in any namespace RootNode.DeclareNamespace('', NsAdobeXfdf); // <-- declare the namespace RootNode.Attributes['xml:space'] := 'preserve'; FNode := RootNode.AddChild('f', NsAdobeXfdf); // <-- f is in the Adobe namespace FNode.Attributes['href'] := 'myExample.pdf'; FieldsNode := RootNode.AddChild('fields', NsAdobeXfdf); // <-- fields is in the Adobe namespace FieldNode := FieldsNode.AddChild('field'); // <-- inherits namespace from fields FieldNode.Attributes['name'] := 'chk01'; FieldNode.AddChild('value').Text := 'X'; // <-- inherits namespace from field FieldNode := FieldsNode.AddChild('field'); // <-- inherits namespace from fields FieldNode.Attributes['name'] := 'chk02'; FieldNode.AddChild('value').Text := 'X'; // <-- inherits namespace from field FieldNode := FieldsNode.AddChild('field'); // <-- inherits namespace from fields FieldNode.Attributes['name'] := 'edt11'; FieldNode.AddChild('value').Text := 'Some text'; // <-- inherits namespace from field XML.SaveToFile('C:\\New.fdf'); end;
  2. alternatively, declare the Adobe namespace on the xfdf node at the time you add that node to the document, and then that node will be in the namespace so the f and fields child nodes inherit it without you having to call DeclareNamespace() manually ( AddChild() calls it internally for you):

     const NsAdobeXfdf = 'http://ns.adobe.com/xfdf/'; var XML: IXMLDocument; RootNode, FNode, FieldsNode, FieldNode: IXMLNode; begin XML := NewXMLDocument; XML.Encoding := 'utf-8'; XML.Options := [doNodeAutoIndent]; RootNode := XML.AddChild('xfdf', NsAdobeXfdf); // <-- xfdf is in the Adobe namespace RootNode.Attributes['xml:space'] := 'preserve'; FNode := RootNode.AddChild('f'); // <-- inherits namespace from xfdf FNode.Attributes['href'] := 'myExample.pdf'; FieldsNode := RootNode.AddChild('fields'); // <-- inherits namespace from xfdf FieldNode := FieldsNode.AddChild('field'); // <-- inherits namespace from fields FieldNode.Attributes['name'] := 'chk01'; FieldNode.AddChild('value').Text := 'X'; // <-- inherits namespace from field FieldNode := FieldsNode.AddChild('field'); // <-- inherits namespace from fields FieldNode.Attributes['name'] := 'chk02'; FieldNode.AddChild('value').Text := 'X'; // <-- inherits namespace from field FieldNode := FieldsNode.AddChild('field'); // <-- inherits namespace from fields FieldNode.Attributes['name'] := 'edt11'; FieldNode.AddChild('value').Text := 'Some text'; // <-- inherits namespace from field XML.SaveToFile('C:\\New.fdf'); end;

Either approach will remove the xmlns="" attribute on the f and fields nodes since they belong to a namespace that is declared in the xfdf node, and subsequent child nodes will inherit the namespace as expected:

<?xml version="1.0" encoding="utf-8"?>
<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">
  <f href="myExample.pdf"/>
  <fields>
    <field name="chk01">
      <value>X</value>
    </field>
    <field name="chk02">
      <value>X</value>
    </field>
    <field name="edt11">
      <value>Some text</value>
    </field>
  </fields>
</xfdf>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM