【问题标题】:How do I get each attribute on its own line when serializing XML?序列化 XML 时如何在自己的行上获取每个属性?
【发布时间】:2013-08-23 11:55:56
【问题描述】:

我正在将配置数据写入 XML 文件。但是XML看起来很不结构化或者怎么说

<Configuration>
  <Ftp Host="LOCALHOST" Port="21"/>
  <Pop3 Host="LOCALHOST" Port="110" Interval="30000"/>
  <Smtp Host="LOCALHOST" Port="25"/>
</Configuration>

我希望它看起来像

<Configuration>
  <Ftp 
        Host="LOCALHOST" 
        Port="21"
    />
  <Pop3 
        Host="LOCALHOST" 
        Port="110" 
        Interval="30000"
    />
  <Smtp 
        Host="LOCALHOST" 
        Port="25"
    />
</Configuration>

有没有可能 这是我的 Delphi 代码的 sn-p。我有所有类型的函数/程序,但这里只显示 2 个

constructor TConnXml.Create(const FileName: string);
begin
  inherited Create;
  fConfigfile     := FileName;
  fXMLDoc         := TXMLDocument.Create(Application);
  fXMLDoc.Options := [doNodeAutoIndent];
  if FileExists(fConfigfile) then
    fXMLDoc.LoadFromFile(fConfigfile)
  else
    begin
      fXMLDoc.Active := True;
      fXMLDoc.AddChild('Configuration');
      fXMLDoc.SaveToFile(fConfigfile);
    end;
end;

constructor TConnXml.Create;
begin
  Create(SettingsFileBuild);
end;

function TConnXml.ReadString(const Section, Key, Default: string): string;
var
  Node: IXMLNode;
begin
  Node := fXMLDoc.DocumentElement.ChildNodes.FindNode(Section);
  if Assigned(Node) and Node.HasAttribute(Key) then
    Result := Node.Attributes[Key]
  else
    Result := Default;
end;

procedure TConnXml.WriteString(const Section, Key, Value: string);
var
  Node: IXMLNode;
begin
  if ReadString(Section, Key, '') = Value then
    Exit;
  Node := fXMLDoc.DocumentElement.ChildNodes.FindNode(Section);
  if not Assigned(Node) then
    Node := fXMLDoc.DocumentElement.AddChild(Section);
  Node.Attributes[Key] := Value;
  fModified := True;
  Save;
end;

procedure TConnXml.Save;
begin
  if not fModified then
    Exit;
  if fBackup then
    CopyFile(PChar(fConfigfile), PChar(fConfigfile + '.bak'), False);
  fXMLDoc.Active := True;
  fXMLDoc.SaveToFile(fConfigfile);
  fModified := False;
end;

function TConnXml.ReadBoolean(const Section, Key: string; Default: Boolean): Boolean;
begin
  Result := Boolean(ReadInteger(Section, Key, Integer(Default)));
end;

procedure TConnXml.WriteBoolean(const Section, Key: string; Value: Boolean);
begin
  WriteInteger(Section, Key, Integer(Value));
end;

【问题讨论】:

  • xml 的主要目的不是供人类阅读。它用于机器与机器之间的通信。您的输出应该是“正确”格式的 XML 输出。为什么你需要另一个外表?如果您真的希望它“看起来”不是 xml,您必须编写自己的 XmlWriter,或者您应该更改为其他格式。
  • 考虑改用TIniFile。编辑 .ini 文件结构中的设置的人不太可能出错,而 XML 是 syntax-heavy
  • 改用 YAML 让它看起来更好
  • 它看起来像格式完美的 XML,具有标准格式(甚至带有特殊的缩进以使其易于阅读)。您可以将 XSL(T) 样式表与它相关联,将其转换为漂亮的 HTML 表示,因此它在浏览器中看起来很整洁。但这可能是矫枉过正。
  • 您已经使用了 doNodeAutoIndent 选项,它使 XML 可读。绰绰有余。

标签: xml delphi xml-formatting


【解决方案1】:

如果您生成此 XML 并且它是用于配置目的,那么使其更具可读性是有其目的的。我经常使用 XML 进行配置,并且仅在真正适用时才使用属性。

我会这样写:

<Configuration>
  <Ftp> 
    <Host>LOCALHOST</Host> 
    <Port>25</Port>
  </Ftp>
  <Pop3> 
    <Host>LOCALHOST/<Host> 
    <Port>110</Port>
    <Interval>30000</Interval>
  </Pop>
  <Smtp> 
    <Host>LOCALHOST</Host> 
    <Port>25</Port>
  </Smtp>
</Configuration>

使用其他格式,然后是 XML,也是一种解决方案。但是,如果您坚持使用 XML,那么我的回答是以人类可读的方式组织 XML 的一种方法。此外,如果您避免使用属性,则例如转换为 JSON 非常简单。

即使 XML 被标记臃肿,我发现如果结构良好,它也是可读的。虽然它是用于计算机数据交换的,但我发现它非常适合配置文件。 YAML 看起来不错,但对我而言,它缺乏明确的结构:)

更新:

由于对代码的请求,我用附加信息更新了答案。要获得像我下面这样的 XML,您所要做的就是更改一个程序。另一方面,这是基本的 XML 处理,所以我建议您学习它。

function TConnXml.ReadString(const Section, Key, Default: string): string;
var
  Node: IXMLNode;
  Child: IXMLNode;
begin
  Node := fXMLDoc.DocumentElement.ChildNodes.FindNode(Section);

  if not Assigned(Node) then 
  begin
    Result := Default;
    Exit;
  end;

  Child:= Node.FindNode(Key);

  if not Assigned(Child) then 
  begin
    Result := Default;
    Exit;
  end;

  Result := Child.Text;
end;

procedure TConnXml.WriteString(const Section, Key, Value: string);
var
  Node: IXMLNode;
  Child: IXMLNode;
begin
  if ReadString(Section, Key, '') = Value then
    Exit;

  Node := fXMLDoc.DocumentElement.ChildNodes.FindNode(Section);

  if not Assigned(Node) then
    Node := fXMLDoc.DocumentElement.AddChild(Section);

  Child:= Node.ChildNodes.FindNode(Key);

  if not Assigned(Child) then
    Child:= Node.AddChild(Key);

  Child.Text := Value;
  fModified := True;
  Save;
end;

我没有测试就写了,所以可能会有一些错误,但这是你应该使用的代码。

【讨论】:

  • YAML 缺乏结构?!!
  • 我写给禁食大卫。我想 YAML 没有什么问题。我只是习惯于 XML 显式标记(使用 字符),因此我实际上导航得更快。但这只是我,我很清楚 YAML 不像 XML 那样臃肿。
  • @Runner 这正是我希望我的文件看起来像的样子。但我还没想好怎么做。如果有人有一些示例代码,我很想看看。
  • @Runner 这使得配置文件在人眼看来至少可读性提高了 100%
猜你喜欢
  • 1970-01-01
  • 2017-05-23
  • 1970-01-01
  • 1970-01-01
  • 2012-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多