Пустой XML-элемент Powershell, отформатированный в одну строку - PullRequest
2 голосов
/ 05 октября 2019

Мне нужно, чтобы мой формат XML немного отличался от способа, которым Powershell сохраняет его по умолчанию. Вот пример кода:

[xml]$XML = New-Object system.Xml.XmlDocument
$Declaration = $XML.CreateXmlDeclaration("1.0","UTF-8",$null)
$XML.AppendChild($Declaration) > $null

$Temp = $XML.CreateElement('Basket')
$Temp.InnerText = $test
$XML.AppendChild($Temp)

$Temp1 = $XML.CreateElement('Item')
$Temp1.InnerText = ''
$Temp.AppendChild($Temp1)

$XML.save('test.xml')

Это приводит к:

<?xml version="1.0" encoding="UTF-8"?>
<Basket>
  <Item>
  </Item>
</Basket>

Мой требуемый XML должен выглядеть следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
<Basket>
  <Item></Item>
</Basket>

Возможно ли это?

Если я добавлю XML.PreserveWhitespace = $true, все закончится на одной строке. И элементы не имеют свойства PreserveWhitespace.

Одно из найденных решений - добавить пробел $Temp1.InnerText = ' ', а затем очистить код на втором шаге. Но мне было интересно, если есть хитрость, чтобы Powershell выводил пустые элементы в одну строку. К сожалению, мое целевое приложение, которому нужно прочитать XML, примет только необходимое выше форматирование.

1 Ответ

2 голосов
/ 05 октября 2019
$Temp1.InnerText = ''

- это ваша попытка заставить сериализацию XML использовать однострочную <tag></tag> форму, а не самозакрывающуюся <tag /> форму , потому что - хотя обе формы если эквивалентно, то конкретный потребитель вашего сериализованного XML (Adobe) принимает только форму <tag></tag>.

Ваша попытка основана на различении действительно пустого элемента - одинкоторый не имеет дочерних узлов - и тот, который имеет пустую строку текст дочерний узел (неявно созданный .InnerText = ''), в надежде, что элемент с дочерними узлами - хотя единственным дочерним узлом является пустая строка - всегда сериализуется в форме <tag>...</tag>.

Ваша попытка:

  • не соблюдается с помощью XmlDocument типа .Save() (который вызвал ваш вопрос)

    • Специфическое поведение, с которым вы столкнулись, должно рассматриваться как ошибка [1] (начиная с .NETCore 3.0) и сообщалось в об этой проблеме GitHub .
  • соблюдается LINQ* на основе XDocument тип, .Save() метод.

Таким образом, у вас есть два варианта:


Обходной путь, если вам дан существующий экземпляр XmlDocument:

Если вы создаете экземпляр XDocument из (не очень напечатанной) XML-строки, возвращаемой .OuterXml вашего экземпляра XmlDocument* свойство ($XML.OuterXml), при сохранении полученного экземпляра XDocument в файл используется требуемая форма <tag></tag>, при условии, что вы сохранили явно добавленный дочерний текстовый узел с пустой строкой в ​​своем коде , т. е. $Temp1.InnerText = '':

# Creates a pretty-printed XML file with the empty elements
# represented in "<tag></tag>" form from the System.Xml.XmlDocument
# instance stored in `$XML`.
([System.Xml.Linq.XDocument] $XML.OuterXml).Save("$PWD/test.xml")

Хотя это требует дополнительного раунда сериализации и синтаксического анализа, это простое и прагматичное решение.

Если объект XML DOM не был предоставлен вам иу вас есть возможность создать его самостоятельно, для начала лучше создать его как экземпляр XDocument, как показано ниже.


AlВ итоге, вы можете создать свой XML-документ напрямую как XmlDocument:

Создание вашего документа как XDocument экземпляра для начала:

# PSv5+ syntax for simplifying type references.
using namespace System.Xml.Linq

# Create the XDocument with its  declaration.
$xd = [XDocument]::new(
        # Note: [NullString]::Value is needed to pass a true null value - $null doesn't wor.
        [XDeclaration]::new('1.0', 'UTF-8', [NullString]::Value)
      )

# Add nodes.
$xd.Add(($basket = [XElement] [XName] 'Basket'))
$basket.Add(($item = [XElement] [XName] 'Item'))

# Add an empty-string child node to the '<Item>' element to
# force it to serialize as '<Item></Item>' rather than as '<Item />'
$item.SetValue('')

# Save the document to a file.
$xd.Save("$PWD/test.xml")

[1] Пробел внутри и элемент имеет значение и считается частью внутреннего текста (значение дочернего текстового узла), поэтому двухстрочное представлениеItem элементы не эквивалентны <Item></Item>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...