2

I'm trying to create an xml document using PowerShell, my issue is that the elements that have been appended to a parent, do not inherit the declare namespace prefix, however whilst playing around, I have managed to get it have the prefix but only with it including another xmlns="".

$UserName = $env:UserName
$OutputPath = "C:\Users\" + $UserName +"\Desktop\Generator\Output\"
$OutputXML = $OutputPath + "Test_File_1.xml"
#Namespace URIs
$VQ5NSX = "http://example2"
$VQ5INTX ="http://example1"
[xml]$Doc = New-Object System.Xml.XmlDocument
$dec = $Doc.CreateXmlDeclaration("1.0","UTF-8",$null)
$doc.AppendChild($dec)

    $root = $doc.CreateNode("element","ns:responsefile", $VQ5NSX)

        $int = $doc.CreateNode("element", "int:IntegrationHeader",$VQ5INTX)

            $IntDt = $doc.CreateElement("int:Date",$null)
                $IntDt.InnerText = "Date Text"
            $Int.AppendChild($IntDt) | Out-Null

            $IntId = $doc.CreateElement("Identification")

                $IntAppID = $doc.CreateElement("ApplicationId")
                    $IntAppIDtxt = $Doc.CreateTextNode("App Id Text")
                $IntAppId.AppendChild($IntAppIDtxt)|Out-Null
            $IntId.AppendChild($IntAppID)|Out-Null

                $IntTransID = $doc.CreateElement("TransactionId")
                    $IntTransIDtxt = $Doc.CreateTextNode("Tran Id Text")
                $IntTransID.AppendChild($IntTransIDtxt) |Out-Null
            $IntId.AppendChild($IntTransID) |Out-Null

            $Int.AppendChild($IntId) |Out-Null
        $root.AppendChild($int)|Out-Null

        $Res = $doc.CreateNode("element","ns:ResponseItem", $null)
            $ItemDetail = $doc.CreateElement("ns:Item1")
                $ItemDetail = $doc.CreateTextNode("Item one text")

            $Res.AppendChild($ItemDetail)|Out-Null
        $root.AppendChild($res)|Out-Null

    $doc.AppendChild($root) |Out-Null  
$doc.save($OutputXML)

This generates the following output;

<?xml version="1.0" encoding="UTF-8"?>
<ns:responsefile xmlns:ns="http://example2">
  <int:IntegrationHeader xmlns:int="http://example1">
    <Date>Date Text</Date>
    <Identification>
      <ApplicationId>App Id Text</ApplicationId>
      <TransactionId>Tran Id Text</TransactionId>
    </Identification>
  </int:IntegrationHeader>
  <ResponseItem>Item one text</ResponseItem>
</ns:responsefile>

However I need it to generate this output;

<?xml version="1.0" encoding="UTF-8"?>
<ns:responsefile xmlns:ns="http://example2">
  <int:IntegrationHeader xmlns:int="http://example1">
    <int:Date>Date Text</Date>
    <int:Identification>
      <int:ApplicationId>App Id Text</int:ApplicationId>
      <int:TransactionId>Tran Id Text</int:TransactionId>
    </int:Identification>
  </int:IntegrationHeader>
  <ns:ResponseItem>Item one text</ns:ResponseItem>
</ns:responsefile>

Any help would be most appreciated!

2
  • What happens if you replace $doc.CreateElement("int:Date",$null) with $doc.CreateElement("int:Date",$VQ5INTX)? The $null appears at a glance to be explicitly saying "don't use a namespace on this element". Commented Jan 16, 2018 at 15:11
  • That seems to have done it, I could have sworn blind I tired that amongst many other things I tried!, Thanks! :) Commented Jan 16, 2018 at 15:24

2 Answers 2

1

Although the definition of the prefix can be inherited by the child nodes, each child node still needs to be specified as in that namespace.

Currently, you are explicitly requesting that the <Date> element is not in any namespace:

$doc.CreateElement("int:Date",$null)

The .net class is assuming you put the int: in by mistake, because an element in no namespace has no prefix.

Instead, you need to specify that the <Date> element is in the http://example1 namespace:

$doc.CreateElement("int:Date",$VQ5INTX)

If the implementation is smart, it will notice that the prefix int is already bound to that namespace, and avoid repeating the xmlns:int attribute (which would be untidy, but not change the document significantly).

Sign up to request clarification or add additional context in comments.

Comments

1

For working with namespaced XML use a namespace manager.

[xml]$doc = @'
<?xml version="1.0" encoding="UTF-8"?>
<ns:responsefile xmlns:ns="http://example2">
  <int:IntegrationHeader xmlns:int="http://example1">
  </int:IntegrationHeader>
  <ResponseItem>Item one text</ResponseItem>
</ns:responsefile>
'@

$int_ns = 'http://example1'

$nsm = New-Object Xml.XmlNamespaceManager($doc.NameTable)
$nsm.AddNamespace('int', $int_ns)

Create the new element in the intended namespace before appending it to the parent node:

$Int = $doc.SelectSingleNode('//int:IntegrationHeader', $nsm)

$IntDt = $doc.CreateElement('int', 'Date', $int_ns)
$IntDt.InnerText = "Date Text"
$Int.AppendChild($IntDt) | Out-Null

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.