I have a XmlDocument which is not properly formed
<library>
<dept>
<books></books>
<language></language>
</dept>
<dept>
<lecturer></lecturer>
</dept>
</library>
I want to do a XmlDocument.SelectSingleNode for 'lecturer' tag.
When I select ChildNodes of <library> tag, I get only <books> and <language> but not <lecturer>.
How do I get XmlNode object of tag?
The XML is well formed XML. It would not load into a XmlDocument otherwise.
The only ChildNodes of library are dept nodes.
To get lecturer, you can do the following:
XmlDocument.SelectSingleNode("library/dept/lecturer");
To parse csproj file, use GetElementsByTagName(). I dont know why SelectSingleNode() is not working!
Thank you
Sid
Related
I have an XML format of this structure (the real world example is horrendously long and complicated, but this should illustrate it):
<document> <post>
<author>Bill Smith</author>
<subject>Test Article</subject>
<dates>
<uploaded>some date</uploaded>
<published>some date</published>
</dates>
</post>
<post>
<author>Bill Smith</author>
<subject>Test Article</subject>
<dates>
<uploaded>some date</uploaded>
<published>some date</published>
</dates>
</post> </document>
I have wrote a simple query to pull out each of the posts. I can get the author and subject fine, but I don't know how to drill down into the dates part to pull out the published bit.
Thanks
You can use the following LINQ to get the first "published" element.
XDocument document = XDocument.Load(#"D:\XMLFile1.xml", LoadOptions.None);
XElement element = document
.Descendants("document")
.Descendants("post")
.Descendants("dates")
.Descendants("published")
.First();
string publishedDate = element.Value;
You can give any expressions as parameter to the 'Descendants' method.
If you have xml as a string, you can use the following to read it into an XDocument
XDocument.Parse();
Please remember to check for nulls!! :-)
i have the string, it contains xml nodes, returned from the PHP file.
It's like
<a>1</a><b>0</b><c>4</c>..............
Now i need to find out what value each node have i.e a, b, c......
while loading this string to xmlDocument i'm getting error like "There are multiple root elements".
any solution for this
One of the basic rules for well-formed XML that it has a single root node. With your example, you have multiple roots:
<a>1</a>
<b>0</b>
<c>4</c>
To make it well-formed you will have to make these elements a child of a single root:
<root>
<a>1</a>
<b>0</b>
<c>4</c>
</root>
An XML document that is not well-formed is not really an XML document at all and you will find that no XML parser will be able to read it!
Wrap it in a root element. E.g:
From <a>1</a><b>2</b>...
To <root><a>1</a><b>2</b>...</root>
Then compute as normal.
That is because each element is at the same level. There need to be a "root" that encloses all of them. Wrap them in a arbitrary node, say <root>...</root> then load the new string to the xmlDocument.
This seems like XML, but it's not valid XML. In XML, you have a root element that wraps all of the other elements.
So, if you have that string in str, do this:
str = String.Format("<root>{0}</root>", str);
I am working on a biztalk project and I need to copy (filtered) content from 1 xml to another.
I have to do this with xpath, I can't use xsl transformation.
So my xpath to get the content from the source xml file is this:
//*[not(ancestor-or-self::IN1_Insurance)]|//IN1_Insurance[2]/descendant-or-self::*
Now this returns an xmlNodelist. Is it possible to return a string with all the nodes in it like:
"<root><node>text</node></root>"
If I put string() before my xpath it returns the values, but I want the whole xml in a string (with nodes..), so I could load that string in another xmldocument. I think this is the best method for my problem.
I know I can loop over the xmlnodelist and append the nodes to the new xmldocument, but it's a bit tricky to loop in a biztalk orchestration and I want to avoid this.
The code I can use is C#.
I've tried to just assign the nodelist to the xmldocument, but this throws a cast error (obvious..).
The way I see it is that I have 2 solutions:
assign the nodelist to the xmldocument without a loop (not possible i think in C#)
somehow convert the nodelist to string and load this in the xmldocument
load the xpath directly in the new xmldocument (don't know if this is possible since it returns a nodelist)
Thanks for your help
edit:
sample input:
<root>
<Patient>
<PatientId></PatientId>
<name></name>
</Patient>
<insurance>
<id>1</id>
<billing></billing>
</insurance
<insurance>
<id>2</id>
<billing></billing>
</insurance>
<insurance>
<id>3</id>
<billing></billing>
</insurance>
</root>
Now I want to copy this sample to another xmldocument, but without insurance node 2 and 3 (this is dynamically, so it could be unsurance node 1 and 2 to delete, or 1 and 3...)
So this has to be the output:
<root>
<Patient>
<PatientId></PatientId>
<name></name>
</Patient>
<insurance>
<id>1</id>
<billing></billing>
</insurance>
</root>
What I am doing now is use the xpath to get the nodes I want. Then I want to assign the result to the new xmldocument, but this is not possible since I get the castException
string xpath = "//*[not(ancestor-or-self::IN1_Insurance)]|//IN1_Insurance[2]/descendant-or-self::*";
xmlDoc = new System.Xml.XmlDocument();
xmlDoc = xpath(sourceXml, strXpath); <= cast error (cannot cast xmlnodelist to xmldocuemnt)
I know the syntax is a bit strange, but it is biztalk c# code..
The most straightforward solution would indeed be to "loop over the xmlnodelist and append (import) the nodes to the new xmldocument", but since you can't loop, what other basic things can/can't you do?
To serialize the nodelist, you could try using XmlNodeList.toString(). If that worked, you'd get a strange beast, because it could be duplicating parts of the XML document several times over. Especially since you're explicitly including ancestors and descendants directly in the nodelist. It would not be something that you could parse back in and have a result that resembled the nodelist you started with.
In other words, it would be best to loop over the XmlNodeList and import the nodes to the new XmlDocument.
But even so, I would be really surprised if you wanted to put all these ancestor and descendant nodes:
//*[not(ancestor-or-self::IN1_Insurance)]|//IN1_Insurance[2]/descendant-or-self::
directly into the new XML document. If you post some sample input and the desired output, we can probably help determine if that's the case.
Update:
I see what you're trying to do: copy an XML document, omitting all <insurance> elements (and their descendants) except the one you want.
This can be done without a loop if the output is as simple as your sample output: only one <Patient> and one <insurance> element, with their descendants, under one top-level element.
Something like (I can't test this as I don't have a biztalk server):
string xpathPatient = "/*/Patient";
string xpathInsuran = "/*/insurance[id = " + insId + "]"; // insId is a parameter
xmlDoc = new System.Xml.XmlDocument();
xmlPatient = xpath(sourceXml, xpathPatient);
xmlInsuran = xpath(sourceXml, xpathInsuran);
XmlElement rootNode = xmlDoc.CreateElement("root");
xmlDoc.AppendChild(rootNode);
//**Update: use [0] to get an XmlNode from the returned XmlNodeList (presumably)
rootNode.AppendChild(xmlDoc.ImportNode(xmlPatient[0], true));
rootNode.AppendChild(xmlDoc.ImportNode(xmlInsuran[0], true));
I confess though, I'm curious why you can't use XSLT. You're approaching tasks that would be more easily done in XSLT than in XPath + C# XmlDocument.
Update: since the xpath() function probably returns an XmlNodeList rather than an XmlNode, I added [0] to the first argument to ImportNode() above. Thanks to #Martin Honnen for alerting me to that.
XPath is a query language (only) for XML documents.
It operates on an abstract model -- the XML INFOSET, and cannot either modify the structure of the XML document(s) it operates on or serialize the INFOSET information items back to XML.
Therefore, the only way to achieve such serialization is to use the language that is hosting XPath.
Apart from this, there are obvious problems with yout question, for example these is no element named IN1_Insurance in the provided XML document -- therefore the XPath expression provided:
//*[not(ancestor-or-self::IN1_Insurance)]|//IN1_Insurance[2]/descendant-or-self::*
selects all elements in the document.
Note:
The described task is elementary to fulfil using XSLT.
Finally: If you are allowed to use C# then you can use the XslCompiledTransform (or XslTransform) class. Use its Transform() method to carry out the following transformation against the XML document:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="insurance[not(id=1)]"/>
</xsl:stylesheet>
This produces exactly the wanted result:
<root>
<Patient>
<PatientId></PatientId>
<name></name>
</Patient>
<insurance>
<id>1</id>
<billing></billing>
</insurance>
</root>
I want to merge two XmlDocuments by inserting a second XML doc to the end of an existing Xmldocument in C#. How is this done?
Something like this:
foreach (XmlNode node in documentB.DocumentElement.ChildNodes)
{
XmlNode imported = documentA.ImportNode(node, true);
documentA.DocumentElement.AppendChild(imported);
}
Note that this ignores the document element itself of document B - so if that has a different element name, or attributes you want to copy over, you'll need to work out exactly what you want to do.
EDIT: If, as per your comment, you want to embed the whole of document B within document A, that's relatively easy:
XmlNode importedDocument = documentA.ImportNode(documentB.DocumentElement, true);
documentA.DocumentElement.AppendChild(importedDocument);
This will still ignore things like the XML declaration of document B if there is one - I don't know what would happen if you tried to import the document itself as a node of a different document, and it included an XML declaration... but I suspect this will do what you want.
Inserting an entire XML document at the end of another XML document is actually guaranteed to produce invalid XML. XML requires that there be one, and only one "document" element. So, assuming that your files were as follows:
A.xml
<document>
<element>value1</element>
<element>value2</element>
</document>
B.xml
<document>
<element>value3</element>
<element>value4</element>
</document>
The resultant document by just appending one at the end of the other:
<document>
<element>value1</element>
<element>value2</element>
</document>
<document>
<element>value3</element>
<element>value4</element>
</document>
Is invalid XML.
Assuming, instead, that the two documents share a common document element, and you want to insert the children of the document element from B into A's document element, you could use the following:
var docA = new XmlDocument();
var docB = new XmlDocument();
foreach (var childEl in docB.DocumentElement.ChildNodes) {
var newNode = docA.ImportNode(childEl, true);
docA.DocumentElement.AppendChild(newNode);
}
This will produce the following document given my examples above:
<document>
<element>value1</element>
<element>value2</element>
<element>value3</element>
<element>value4</element>
</document>
This is the fastest cleanest way to merge xml documents.
XElement xFileRoot = XElement.Load(file1.xml);
XElement xFileChild = XElement.Load(file2.xml);
xFileRoot.Add(xFileChild);
xFileRoot.Save(file1.xml);
Bad news. As long as the xml documents can have only one root element you cannot just put content of one document at the end of the second. Maybe this is what you are looking for? It shows how easily you can merge xml files using Linq-to-XML
Alternatively if you are using XmlDocuments you can try make it like this:
XmlDocument documentA;
XmlDocument documentB;
foreach(var childNode in documentA.DocumentElement.ChildNodes)
documentB.DocumentElement.AppendChild(childNode);
How can I append an XML document to an xml node in c#?
An XmlDocument is basically an XmlNode, so you can append it just like you would do for any other XmlNode. However, the difference arises from the fact that this XmlNode does not belong to the target document, therefore you will need to use the ImportNode method and then perform the append.
// xImportDoc is the XmlDocument to be imported.
// xTargetNode is the XmlNode into which the import is to be done.
XmlNode xChildNode = xSrcNode.ImportNode(xImportDoc, true);
xTargetNode.AppendChild(xChildNode);
Yes:
XmlNode imported = targetNode.OwnerDocument.ImportNode(otherDocument.DocumentElement, true);
targetNode.AppendChild(imported);
I think this creates a clone of your document though.
Perhaps like this:
XmlNode node = ...... // belongs to targetDoc (XmlDocument)
node.AppendChild(targetDoc.ImportNode(xmlDoc.DocumentElement));
Marc
Let's say you have the following construction:
The following structure is stored in an XmlElement named xmlElement:
</root>
and the following structure is stored in an XmlNode object named FooNode;
<foo>
<bar>This is a test</bar>
<baz>And this is another test</baz>
</foo>
Then you do the following:
XmlNode node = doc.ImportNode(FooNode.SelectSingleNode("foo"), true);
xmlElement.AppendChild(node);
Hope it helps someone
Once you have the root node of the XML document in question you can append it as a child node of the node in question. Does that make sense?