Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><code>LoadXMLData()</code> expects the input string to be a well-formed XML document. The solution I gave you for your previous question worked because you were specifying individual XML elements which by themselves can act be standalone documents. But a PCDATA element by itself is not a well-formed XML document. Try wrapping it in a fake element, eg:</p> <pre><code>tmpDoc := LoadXMLData('&lt;Doc&gt;' + MissingElements[j] + '&lt;/Doc&gt;').DocumentElement; for I := 0 to tmpDoc.ChildNodes.Count-1 do tmpNode.ChildNodes[1].ChildNodes[0].ChildNodes.Add(tmpDoc.ChildNodes[I]); </code></pre> <p><strong>Update:</strong> You are getting an "index out of bounds" error because you are not taking the whitespace DOM nodes into account when accessing the <code>ChildNodes</code>.</p> <p>Given the XML you have shown:</p> <pre><code>XMLStarting.Add('&lt;?xml version="1.0" encoding="UTF-16" standalone="no"?&gt;'); XMLStarting.Add('&lt;Programs&gt;'); XMLStarting.Add(' &lt;Program_Group Batch_No="{12345678-1234-1234-1234-123456789ABC}" Description="FOO_824_1"&gt;'); XMLStarting.Add(' &lt;Program Name="PROG_1"&gt;'); XMLStarting.Add(' &lt;Class Name="CLASS_1"&gt;'); XMLStarting.Add(' &lt;Property Name="DB" RttiType="tkString"&gt; &lt;/Property&gt;'); XMLStarting.Add(' &lt;Property Name="SystemDate" RttiType="tkClass" ClassType="TXSDATE"&gt;12/30/1899&lt;/Property&gt;'); XMLStarting.Add(' &lt;/Class&gt;'); XMLStarting.Add(' &lt;/Program&gt;'); XMLStarting.Add(' &lt;/Program_Group&gt;'); XMLStarting.Add('&lt;/Programs&gt;'); </code></pre> <p>And given the code you have shown which is failing:</p> <pre><code>FragNode := storedXMLObj.DocumentElement.ChildNodes[0]; FragNode.ChildNodes.Nodes[0].ChildNodes.Nodes[0].ChildNodes.Add(LoadXMLData(XMLFragment.Text).DocumentElement.ChildNodes.Nodes[0]); </code></pre> <p>The following is true:</p> <ol> <li><code>storedXMLObj.DocumentElement</code> refers to the <code>&lt;Programs&gt;</code> node.</li> <li>its <code>ChildNodes[0]</code> node refers to <strong>the whitespace between the <code>&lt;Programs&gt;</code> and <code>&lt;Program_Group&gt;</code> nodes</strong>, but you are expecting it to refer to the <code>&lt;Program_Group&gt;</code> node instead.</li> <li>thus, <code>FragNode.ChildNodes.Nodes[0]</code> fails because <strong>FragNode is a text-only node that has no children!</strong></li> </ol> <p>You can confirm that for yourself. <code>FragNode.NodeName</code> is <code>'#text'</code>, <code>FragNode.NodeType</code> is <code>ntText</code>, <code>FragNode.NodeValue</code> is <code>#$A' '</code>, <code>FragNode.HasChildNodes</code> is False, and <code>FragNode.IsTextElement</code> is True.</p> <p>In other words, the above XML has the following structure to it:</p> <pre><code>ntElement 'Programs' | |_ ntText #$A' ' | |_ ntElement 'Program_Group' | |_ ntText #$A' ' | |_ ntElement 'Program' | | | |_ ntText #$A' ' | | | |_ ntElement 'Class' | | | | | |_ ntText #$A' ' | | | | | |_ nElement 'Property' | | | | | | | |_ ntText ' ' | | | | | |_ ntText #$A' ' | | | | | |_ ntElement 'Property' | | | | | | | |_ ntText '12/30/1899' | | | | | |_ ntText #$A' ' | | | |_ ntText #$A' ' | |_ ntText #$A' ' </code></pre> <p>Hopefully that makes it a bit clearer.</p> <p>So, to accomplish what you are attempting to do, you would need something more like this:</p> <pre><code>FragNode := storedXMLObj.DocumentElement.ChildNodes[1]; FragNode.ChildNodes.Nodes[1].ChildNodes.Nodes[1].ChildNodes.Add(LoadXMLData(XMLFragment.Text).DocumentElement); FragNode.ChildNodes.Nodes[1].ChildNodes.Nodes[1].ChildNodes.Add(LoadXMLData(XMLFragment.Text).DocumentElement); </code></pre> <p>If you want to preserve whitespace in the <code>LoadXMLData()</code> fragments, you will have to use TXMLDocument directly instead since <code>LoadXMLData()</code> does not let you set the <code>poPreserveWhiteSpace</code> flag:</p> <pre><code>FragmentXMLObj := TXMLDocument.Create(self); FragmentXMLObj.ParseOptions := FragmentXMLObj.ParseOptions + [poPreserveWhiteSpace]; FragmentXMLObj.Options := [doNodeAutoCreate, doNodeAutoIndent]; FragmentXMLObj.LoadFromXML(XMLFragment.Text); FragNode.ChildNodes.Nodes[1].ChildNodes.Nodes[1].ChildNodes.Add(FragmentXMLObj.DocumentElement); FragmentXMLObj.Free; </code></pre> <p>To avoid any problem with <code>ChildNodes</code> indexes, you are better off using an XPath query instead, so you can let the DOM search for the <code>&lt;Class&gt;</code> node that you want to insert fragments into.</p> <p>Either way, you will soon discover that this does not produce very nice looking XML. If you just want there to be whitespace present, but you don't actually need to preserve the original whitespace as-is, then you are better off disabling the <code>poPreserveWhiteSpace</code> flag, and then use <code>FormatXMLData()</code> when you are saving the final document:</p> <pre><code>XMLMerged.Text := FormatXMLData(StoredXMLObj.XML.Text); </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload