Мне нужно преобразовать все атрибуты в узлы в файле XML, за исключением атрибутов в корневом узле.
Я нашел похожий вопрос здесь: xquery для преобразования атрибутов в теги , но мне нужно выполнить преобразование в C #.
Я также нашел возможное решение с использованием XLS здесь: Преобразовать значение атрибута в элемент . Однако это решение существенно меняет имя узла на имя атрибута и удаляет атрибут.
Мне нужно создать новые узлы-братья с именем и значением атрибутов и удалить атрибуты, но при этом сохранить узел, содержащий атрибуты.
С учетом следующего XML:
<Something xmlns="http://www.something.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xomething.com segments.xsd">
<Version>4.0.8</Version>
<Segments>
<Segment Name="Test">
<SegmentField>
<SegmentIndex>0</SegmentIndex>
<Name>RecordTypeID</Name>
<Value Source="Literal">O</Value>
</SegmentField>
<SegmentField>
<SegmentIndex>1</SegmentIndex>
<Name>OrderSequenceNumber</Name>
<Value Source="Calculated" Initial="1">Sequence</Value>
</SegmentField>
<SegmentField>
<SegmentIndex>3</SegmentIndex>
<Name>InstrumentSpecimenID</Name>
<Value Source="Property">BarCode</Value>
</SegmentField>
</Segment>
</Segments>
</Something>
Мне нужно создать следующий XML:
<Something xmlns="http://www.something.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xomething.com segments.xsd">
<Version>4.0.8</Version>
<Segments>
<Segment>
<Name>Test</Name>
<SegmentField>
<SegmentIndex>0</SegmentIndex>
<Name>RecordTypeID</Name>
<Value>O</Value>
<Source>Literal</Source>
</SegmentField>
<SegmentField>
<SegmentIndex>1</SegmentIndex>
<Name>OrderSequenceNumber</Name>
<Value>Sequence</Value>
<Source>Calculated</Source>
<Initial>1</Initial>
</SegmentField>
<SegmentField>
<SegmentIndex>3</SegmentIndex>
<Name>InstrumentSpecimenID</Name>
<Value>BarCode</Value>
<Source>Property</Source>
</SegmentField>
</Segment>
</Segments>
</Something>
Я написал следующий метод для создания нового объекта XML, создавая новые элементы из атрибутов элемента source
:
private static XElement ConvertAttribToElement(XElement source)
{
var result = new XElement(source.Name.LocalName);
if (source.HasElements)
{
foreach (var element in source.Elements())
{
var orphan = ConvertAttribToElement(element);
result.Add(orphan);
}
}
else
{
result.Value = source.Value.Trim();
}
if (source.Parent == null)
{
// ERROR: The prefix '' cannot be redefined from '' to 'http://www.something.com' within the same start element tag.
//foreach (var attrib in source.Attributes())
//{
// result.SetAttributeValue(attrib.Name.LocalName, attrib.Value);
//}
}
else
{
while (source.HasAttributes)
{
var attrib = source.LastAttribute;
result.AddFirst(new XElement(attrib.Name.LocalName, attrib.Value.Trim()));
attrib.Remove();
}
}
return result;
}
Этот метод создает следующий XML:
<Something>
<Version>4.0.8</Version>
<Segments>
<Segment>
<Name>Test</Name>
<SegmentField>
<SegmentIndex>0</SegmentIndex>
<Name>RecordTypeID</Name>
<Value>
<Source>Literal</Source>O</Value>
</SegmentField>
<SegmentField>
<SegmentIndex>1</SegmentIndex>
<Name>OrderSequenceNumber</Name>
<Value>
<Source>Calculated</Source>
<Initial>1</Initial>Sequence</Value>
</SegmentField>
<SegmentField>
<SegmentIndex>3</SegmentIndex>
<Name>InstrumentSpecimenID</Name>
<Value>
<Source>Property</Source>BarCode</Value>
</SegmentField>
</Segment>
</Segments>
</Something>
Есть две непосредственные проблемы с выводом:
1) Атрибуты в корневом элементе потеряны.
2) Атрибуты из элемента «Значение» создаются как дочерние элементы вместо родных элементов.
Чтобы решить первую проблему, я попытался присвоить атрибуты элемента source
элементу result
, но если это вызвало префикс "", его нельзя переопределить с '' на 'http://www.something.com' в том же теге начального элемента"ошибка. Я закомментировал код, который вызвал ошибку для иллюстрации.
Для решения второй проблемы я попытался добавить элемент, созданный из атрибута, к элементу source.Parent
, но это привело к тому, что новый элемент вообще не появился.
Я также переписал метод для работы непосредственно с элементом source
:
private static void ConvertAttribToElement2(XElement source)
{
if (source.HasElements)
{
foreach (var element in source.Elements())
{
ConvertAttribToElement2(element);
}
}
if (source.Parent != null)
{
while (source.HasAttributes)
{
var attrib = source.LastAttribute;
source.Parent.AddFirst(new XElement(attrib.Name.LocalName, attrib.Value.Trim()));
attrib.Remove();
}
}
}
Перезапись произвела следующий XML:
<Something xmlns="http://www.something.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xomething.com segments.xsd">
<Version>4.0.8</Version>
<Segments>
<Name xmlns="">Test</Name>
<Segment>
<SegmentField>
<Source xmlns="">Literal</Source>
<SegmentIndex>0</SegmentIndex>
<Name>RecordTypeID</Name>
<Value>O</Value>
</SegmentField>
<SegmentField>
<Source xmlns="">Calculated</Source>
<Initial xmlns="">1</Initial>
<SegmentIndex>1</SegmentIndex>
<Name>OrderSequenceNumber</Name>
<Value>Sequence</Value>
</SegmentField>
<SegmentField>
<Source xmlns="">Property</Source>
<SegmentIndex>3</SegmentIndex>
<Name>InstrumentSpecimenID</Name>
<Value>BarCode</Value>
</SegmentField>
</Segment>
</Segments>
</Something>
Перезапись did решает первую проблему сохранения атрибутов корневого элемента. Это также частично решило вторую проблему, но породило новую проблему: новые элементы имеют пустой атрибут xmlns.