Переименование имен элементов XDocument - PullRequest
1 голос
/ 30 сентября 2019

У меня проблемы с переименованием имен элементов XML. Я пытаюсь добиться следующего.

Ввод:

<Addresses>
    <AddressItem>
        <AddressLine1>RZN850PXKYG</AddressLine1>
        <AddressLine2>RYK57IT7Y9Z</AddressLine2>
        <AddressType>Physical</AddressType>
        <City>Some City</City>
        <PostalCode>9999</PostalCode>
        <Province>Some Province</Province>
        <Suburb>Some Suburb</Suburb>
    </AddressItem>
</Addresses>

Ожидаемый результат:

<b:Addresses>
    <b:AddressItem>
        <b:AddressLine1>RZN850PXKYG</b:AddressLine1>
        <b:AddressLine2>RYK57IT7Y9Z</b:AddressLine1>
        <b:AddressType>Physical</b:AddressType>
        <b:City>Some City</b:City>
        <b:PostalCode>9999</b:PostalCode>
        <b:Province>Some Province</b:Province>
        <b:Suburb>Some Suburb</b:Suburb>
    </b:AddressItem>
</b:Addresses>

Ранее я успешно добавил атрибуты и переименовал элементы, используя что-то похожее на это:

var xmlDoc = XDocument.Parse(requestObj);

foreach (var element in xmlDoc.Descendants())
{
    if (element.Name.LocalName.StartsWith("something"))
    {
        //example rename element
        element.Name = "request";

        XNamespace b = "http://schemas.something.org/bla/07/WebServices.Stuff";
        XNamespace i = "http://www.w3.org/2001/XMLSchema-instance";

        //set it's attributes
        element.SetAttributeValue(XNamespace.Xmlns + "b", b);
        element.SetAttributeValue(XNamespace.Xmlns + "i", i);
    }
}

Я пытался достичь ожидаемого результата, просто используя приведенный ниже код, но двоеточие вызывает у меня проблемы:

foreach (var element in xmlDoc.Descendants())
{
    element.Name = "b:" + element.Name;
}

Я искал, используя полученное сообщение об ошибке (System.Xml.XmlException: 'The ':' character, hexadecimal value 0x3A, cannot be included in a name.'), но ни одно из решений не подходит для элементов, требующих рекурсивного переименования.

1 Ответ

1 голос
/ 01 октября 2019

Предполагая, что <Addresses> - это некоторый вложенный элемент в вашем XML-документе, а некоторый узел верхнего уровня должен объявить пространство имен xmlns:b="http://schemas.something.org/bla/07/WebServices.Stuff", вы можете изменить свой XML следующим образом:

XNamespace newNamespace = "http://schemas.something.org/bla/07/WebServices.Stuff";

// Move Addresses elements and children into the new namespace
foreach (var e in xmlDoc.Descendants().Where(a => a.Name.LocalName == "Addresses").SelectMany(a => a.DescendantsAndSelf()))
{
    e.Name = newNamespace + e.Name.LocalName;
}

// Optionally assign the namespace prefix "b" to some container element in scope.
xmlDoc.Root.SetAttributeValue(XNamespace.Xmlns + "b", newNamespace.NamespaceName);

Примечания:

  1. Вы пытаетесь изменить свойство Name выбранных XElement объектов, чтобы оно было "b:"+element.Name;, однако XElement.Nameэто не string, это XName, который инкапсулирует пространство имен XML и локальное имя, а не пространство имен XML префикс и локальное имя. Таким образом, попытка присвоить Name определенному префиксу не удалась и выдает исключение.

    В LINQ-to-XML объекты XElement не знают своего пространства имен prefix . Они знают свое реальное пространство имен . Только при выводе XElement в строку XML XmlWriter будет пытаться определить префикс пространства имен, ища объявление xmlns в области видимости - или, если ни одна не находится в области видимости, тогда будет выдан соответствующий xmlns объявление автоматически для текущего элемента.

    Таким образом, чтобы изменить элемент так, чтобы он выглядел как <b:Addresses>, необходимо изменить его фактическое пространство имен так, чтобы b: соответствовало. Теперь вы можете не заботиться о точном выбранном префиксе, но если вы это сделаете, вы можете впоследствии указать его для некоторого соответствующего элемента в области, например корневого элемента.

    Демо-скрипта # 1 здесь .

  2. Если вам не нужен конкретный используемый префикс, вы можете полностью пропустить код // Optionally, а .Net XmlWriter автоматически добавит для вас объявления пространства имен.

    Демонстрационная скрипка № 2 здесь .

...