I am trying to escape a colon in the CreateElement method. So for example I want to change the following:
$node = $xmldoc.CreateElement("test:example")
To give me a node that looks like this:
<test:example>
But I unfortunately only get this:
<example>
The Microsoft documentation on this method states that anything preceding a colon gets used as the prefix property and the rest is the LocalName. The prefix doesn't appear in the node, so I want to do a workaround that outputs the colon but doesn't classify the first part as the prefix.
I tried using a baskslash to escape it and generally looked for different ways to do it on other threads, but oftentimes the answer is to avoid the situation where you have to escape the character in the first place. I can't avoid it though because I have no say in the overall expected XML structure.
Preface:
System.Xml.XmlDocument.CreateAttribute()
, with differences where noted.Martin Honnen has provided the crucial pointer:
If you use a namespace prefix in your element name, you must provide the corresponding namespace URI to the System.Xml.XmlDocument.CreateElement()
call, as the second argument:
$node = $xmldoc.CreateElement('test:example', 'https://example.org')
Alternatively, use the overload where you specify the prefix separately:
$node = $xmldoc.CreateElement('test', 'example', 'https://example.org')
Note:
If you neglect to pass a namespace URI, your prefix (test:
) is quietly ignored and removed from the element name - even if the specified prefix is defined in the owner document.
If you do pass a URI, and both the prefix and the URI match an existing namespace definition in the owner document, the new element / attribute is used as specified (without a then-redundant element-level definition of the prefix).
Otherwise, an element-level namespace definition is created for the given prefix (e.g., <test:example xmlns:test="https://example.org" />
)
Conversely, if you pass a namespace URI but no prefix:
with .CreateElement()
, the specified namespace URI is made the default namespace for your (non-prefixed) new element (e.g., <example xmlns="https://example.org" />
), unless the specified URI matches the owner document's default namespace, in which case this (then-redundant) element-level definition is omitted.
That is - unlike with attributes, see below - a prefix defined in the owner document for the same URI is not applied.
with .CreateAttribute()
:
<foo d0p1:example="" xmlns:d0p1="https://example1.org" />
).A self-contained example, focused on elements only:
# Create a sample document that declares a 'test' same prefix with
# a sample namespace URI.
$sampleNamespaceUri = 'https://example.org'
$doc = [xml] "<foo xmlns:test=`"$sampleNamespaceUri`"/>"
# Create the new element.
# NOTE:
# * Even though the owner document knows prefix 'test', you must still
# pass the corresponding namespace URI explcitly.
# * If the URI *differs* from the one associated with 'test' in the owner
# document, the prefix will be *redefined as part your element*, i.e.
# a 'xmlns:test="<different-URI>' attribute will be added to it.
$node = $doc.CreateElement('test:me', $sampleNamespaceUri)
# Append the element as a child node.
$null = $doc.foo.AppendChild($node)
# Print the modified document's XML text.
$doc.OuterXml
Output (prettied):
<foo xmlns:test="https://example.org">
<test:me />
</foo>
Note: If the namespace URIs hadn't matched, you'd see something like the following - note the redefinition of the prefix at the level of the newly inserted element:
<foo xmlns:test="https://example.org">
<test:me xmlns:test="https://different.example.org" />
</foo>