Как получить каждый атрибут в отдельной строке при сериализации XML?
Я пишу данные конфигурации в файл 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 для этого. У меня есть функции / процедуры для всех типов, но просто показывает 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;
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;
Я написал это без тестирования, поэтому могут быть некоторые ошибки, но это код, который вы должны использовать.