How do I add the char : to an XML element attribute?
Here is how the output should look like
<alto xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.loc.gov/standards/alto/ns-v3#"
xsi:schemaLocation="http://www.loc.gov/standards/alto/ns-v3# http://www.loc.gov/standards/alto/v3/alto-3-1.xsd" SCHEMAVERSION="3.1"
xmlns:xlink="http://www.w3.org/1999/xlink">
and so far this is my code
var z = doc.Descendants("alto").First();
XNamespace ns = "http://www.w3.org/2001/XMLSchema-instance";
z.Add(new XAttribute(XNamespace.Xmlns + "xsi", ns.NamespaceName));
I tried this code, but it gives me error
new XAttribute("xmlns", "http://www.loc.gov/standards/alto/ns-v3#")
and here is the error message:
The prefix '' cannot be redefined from '' to 'http://www.loc.gov/standards/alto/ns-v3#' within the same start element tag
You should put default namespace last. For complex namespaces like yours I usually just parse the string like code below :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string xml =
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
"<alto xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
" xmlns=\"http://www.loc.gov/standards/alto/ns-v3#\"" +
" xsi:schemaLocation=\"http://www.loc.gov/standards/alto/ns-v3# http://www.loc.gov/standards/alto/v3/alto-3-1.xsd\" SCHEMAVERSION=\"3.1\"" +
" xmlns:xlink=\"http://www.w3.org/1999/xlink\">" +
"</alto>";
XDocument doc = XDocument.Parse(xml);
XElement root = doc.Root;
XNamespace ns = root.GetDefaultNamespace();
XNamespace nsXsi = root.GetNamespaceOfPrefix("xsi");
XNamespace nsSchemaLocation = root.GetNamespaceOfPrefix("schemaLocation");
XNamespace nsXlink = root.GetNamespaceOfPrefix("xlink");
}
}
}
Related
In an xsl-fo file how can I remove some elements
Quickest way, perhaps not the most elegant :
XmlDocument xmlDoc = new XmlDocument();
StringBuilder xmlSb = new StringBuilder();
xmlSb.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
xmlSb.AppendLine("<fo:root xmlns:fo=\"http://www.w3.org/1999/XSL/Format\">");
xmlSb.AppendLine(" <fo:layout-master-set>");
xmlSb.AppendLine(" <fo:simple-page-master master-name=\"master\">");
xmlSb.AppendLine(" <fo:region-body margin-bottom=\"0.5in\" margin-top=\"0.9in\" margin-left=\"35pt\"/>");
xmlSb.AppendLine(" <fo:region-before region-name=\"xsl-region-before\" extent=\"0.9in\"/>");
xmlSb.AppendLine(" <fo:region-after region-name=\"xsl-region-after\" extent=\"0.5in\"/>");
xmlSb.AppendLine(" </fo:simple-page-master>");
xmlSb.AppendLine(" </fo:layout-master-set>");
xmlSb.AppendLine(" <fo:page-sequence master-reference=\"master\"/>");
xmlSb.AppendLine("</fo:root>");
// Load xml from string
xmlDoc.LoadXml(xmlSb.ToString());
Console.WriteLine("----- Original xml -----");
Console.WriteLine(xmlSb.ToString());
// Select region-before node
XmlNode regionBeforeNode = xmlDoc.SelectSingleNode("//*[local-name()='region-before']");
// Remove region-before node
regionBeforeNode.ParentNode.RemoveChild(regionBeforeNode);
// Select region-after node
XmlNode regionAfterNode = xmlDoc.SelectSingleNode("//*[local-name()='region-after']");
// Remove region-after node
regionAfterNode.ParentNode.RemoveChild(regionAfterNode);
Console.WriteLine("----- Nodes removed -----");
StringBuilder sbOut = new StringBuilder();
// Pretty indented output
XmlWriterSettings settings = new XmlWriterSettings
{
Indent = true,
IndentChars = " ",
NewLineChars = "\r\n",
NewLineHandling = NewLineHandling.Replace
};
using (XmlWriter writer = XmlWriter.Create(sbOut, settings))
{
xmlDoc.Save(writer);
}
Console.WriteLine(sbOut.ToString ());
Try xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication11
{
class Program
{
static void Main(string[] args)
{
string xml =
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
"<fo:root xmlns:fo=\"http://www.w3.org/1999/XSL/Format\">" +
" <fo:layout-master-set>" +
" <fo:simple-page-master master-name=\"master\">" +
" <fo:region-body margin-bottom=\"0.5in\" margin-top=\"0.9in\" margin-left=\"35pt\"/>" +
" </fo:simple-page-master>" +
" </fo:layout-master-set>" +
" <fo:page-sequence master-reference=\"master\"/>" +
"</fo:root>";
XDocument doc = XDocument.Parse(xml);
XNamespace nsFo = doc.Root.GetNamespaceOfPrefix("fo");
XElement regionBody = doc.Descendants(nsFo + "region-body").FirstOrDefault();
regionBody.Add(new XElement(nsFo + "test", new object[] { new XAttribute("name", "John")}));
}
}
}
Question update: im very sorry if my question is not clear
here is the code im using right now
XDocument doc = XDocument.Parse(framedoc.ToString());
foreach (var node in doc.Descendants("document").ToList())
{
XNamespace ns = "xsi";
node.SetAttributeValue(ns + "schema", "");
node.Name = "alto";
}
and here is the output
<alto p1:schema="" xmlns:p1="xsi">
my goal is like this
xsi:schemaLocation=""
where does the p1 and xmlns:p1="xsi" came from?
When you write
XNamespace ns = "xsi";
That's creating an XNamespace with a URI of just "xsi". That's not what you want. You want a namespace alias of xsi... with the appropriate URI via an xmlns attribute. So you want:
XDocument doc = XDocument.Parse(framedoc.ToString());
foreach (var node in doc.Descendants("document").ToList())
{
XNamespace ns = "http://www.w3.org/2001/XMLSchema-instance";
node.SetAttributeValue(XNamespace.Xmnls + "xsi", ns.NamespaceName);
node.SetAttributeValue(ns + "schema", "");
node.Name = "alto";
}
Or better, just set the alias at the root element:
XDocument doc = XDocument.Parse(framedoc.ToString());
XNamespace ns = "http://www.w3.org/2001/XMLSchema-instance";
doc.Root.SetAttributeValue(XNamespace.Xmlns + "xsi", ns.NamespaceName);
foreach (var node in doc.Descendants("document").ToList())
{
node.SetAttributeValue(ns + "schema", "");
node.Name = "alto";
}
Sample creating a document:
using System;
using System.Xml.Linq;
public class Test
{
static void Main()
{
XNamespace ns = "http://www.w3.org/2001/XMLSchema-instance";
XDocument doc = new XDocument(
new XElement("root",
new XAttribute(XNamespace.Xmlns + "xsi", ns.NamespaceName),
new XElement("element1", new XAttribute(ns + "schema", "s1")),
new XElement("element2", new XAttribute(ns + "schema", "s2"))
)
);
Console.WriteLine(doc);
}
}
Output:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<element1 xsi:schema="s1" />
<element2 xsi:schema="s2" />
</root>
So, I try creating Xml document with next code:
XNamespace spr1 = "urn:schemas-microsoft-com:office:spreadsheet";
XNamespace ex = "urn:schemas-microsoft-com:office:excel";
XNamespace spr2 = "urn:schemas-microsoft-com:office:spreadsheet";
XNamespace rec = "http://www.w3.org/TR/REC-html40";
var xworkbook = new XElement(spr1 + "Workbook");
xworkbook.Add(new XAttribute(XNamespace.Xmlns + "x", ex));
xworkbook.Add(new XAttribute(XNamespace.Xmlns +"ss", spr2));
xworkbook.Add(new XAttribute(XNamespace.Xmlns + "html", rec));
This code make next xml:
<ss:Workbook xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
<!--Xml body-->
</ss:Workbook>
But I expect this:
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
</Workbook>
How to build Workbook element without "ss" prefix and with needed "xmlns" attribute?
LINQ to XML uses the namespace prefix that is closest as it looks through all the attributes in reverse order from the current element to the root. So if you add the default namespace explicitly at the end, then Workbook will use that and not the ss prefix.
XNamespace ss = "urn:schemas-microsoft-com:office:spreadsheet";
XNamespace ex = "urn:schemas-microsoft-com:office:excel";
XNamespace html = "http://www.w3.org/TR/REC-html40";
var workbook = new XElement(
ss + "Workbook",
new XAttribute(XNamespace.Xmlns + "x", ex),
new XAttribute(XNamespace.Xmlns + "ss", ss),
new XAttribute(XNamespace.Xmlns + "html", html),
new XAttribute("xmlns", ss)
);
This gives you the XML below:
<Workbook xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40"
xmlns="urn:schemas-microsoft-com:office:spreadsheet" />
As stated in the comments, the two documents in your question are semantically the same. Any XML parser shouldn't care about the difference between the two documents.
I usually do it like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string xml =
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>" +
"<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"" +
" xmlns:x=\"urn:schemas-microsoft-com:office:excel\"" +
" xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\"" +
" xmlns:html=\"http://www.w3.org/TR/REC-html40\">" +
"</Workbook>";
XDocument doc = XDocument.Parse(xml);
XElement workbook = (XElement)doc.FirstNode;
XNamespace ssNs = workbook.GetNamespaceOfPrefix("ss");
XElement worksheet = new XElement(ssNs + "Worksheet");
workbook.Add(worksheet);
}
}
}
I have an XML string which looks like below
<?xml version="1.0" encoding="Windows-1252"?><Product><ID>0701161476416</ID><UNIQUE_ID>test26051602</UNIQUE_ID><STATUS>DONE</STATUS></Product>
It is know that my XML string will always has a single node ans so I do not want to look, instead I would like to get Unique_ID and Status inner values without looping.
May I know a better way to do it and I do have the below code which actually loops through each node
XmlDocument xm = new XmlDocument();
xm.LoadXml(XML_STRING);
XmlNodeList xnList = xm.SelectNodes("/Product/Product");
foreach (XmlNode xn in xnList)
{
string uniqueID = xn["UNIQUE_ID"].InnerText;
string status = xn["STATUS"].InnerText;
}
There is SelectSingleNode() which you can use for this purpose :
XmlNode product = xm.SelectSingleNode("/Product/Product");
string uniqueID = product["UNIQUE_ID"].InnerText;
string status = product["STATUS"].InnerText;
Or, if Product is the root element, then you can access it from DocumentElement property of the XmlDocument :
XmlNode product = xm.DocumentElement;
string uniqueID = product["UNIQUE_ID"].InnerText;
string status = product["STATUS"].InnerText;
If you have more than one product try xml linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string xml =
"<?xml version=\"1.0\" encoding=\"Windows-1252\"?>" +
"<Products>" +
"<Product>" +
"<ID>0701161476416</ID>" +
"<UNIQUE_ID>test26051603</UNIQUE_ID>" +
"<STATUS>DONE</STATUS>" +
"</Product>" +
"<Product>" +
"<ID>0701161476417</ID>" +
"<UNIQUE_ID>test26051604</UNIQUE_ID>" +
"<STATUS>DONE</STATUS>" +
"</Product>" +
"<Product>" +
"<ID>0701161476418</ID>" +
"<UNIQUE_ID>test26051605</UNIQUE_ID>" +
"<STATUS>DONE</STATUS>" +
"</Product>" +
"</Products>";
XDocument doc = XDocument.Parse(xml);
var results = doc.Descendants("Product").Select(x => new
{
id = (long)x.Element("ID"),
uniqueID = (string)x.Element("UNIQUE_ID"),
status = (string)x.Element("STATUS")
}).ToList();
}
}
}
This could work, but I guess there is a better solution:
XDocument xm = XDocument.Parse(XML_STRING);
var product = xm.Element("Product").Element("Product");
string uniqueID = product.Element("UNIQUE_ID").Value;
string status = product.Element("STATUS").Value;
Your SelectNodes line seemed wrong for the sample Xml.
XmlNodeList xnList = xm.SelectNodes("/Product");
if (xnList.Count > 0)
{
string uniqueID = xnList[0]["UNIQUE_ID"].InnerText;
string status = xnList[0]["STATUS"].InnerText;
}
I have a text file contains 500+ xmlelements like the following:
<Data a="a" b="b" c="c" d="d"><Date runDt="01-01-1900" /></Data>
Can someone please show me how to read/load it so I can retrieve certain attributes/elements? And once I manipulate the data, write it back to a new text file (and needs to be a .txt file without any xml headers).
Thanks :)
Easiest way is to use:
using System.Xml;
XmlDocument xml = new XmlDocument ();
xml.InnerXml = #"<Data a=\"a\" b=\"b\" c=\"c\" d=\"d\"><Date runDt=\"01-01-1900\" /></Data>";
Console.WriteLine (xml.ChildNodes [0].Attributes [0].InnerText);
Will print
a
Using XmlDocument is very easy, just check its fields, variables and methods.
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string input =
"<Data a=\"a\" b=\"b\" c=\"c\" d=\"d\"><Date runDt=\"01-01-1900\" /></Data>\n" +
"<Data a=\"a\" b=\"b\" c=\"c\" d=\"d\"><Date runDt=\"01-01-1900\" /></Data>\n" +
"<Data a=\"a\" b=\"b\" c=\"c\" d=\"d\"><Date runDt=\"01-01-1900\" /></Data>\n" +
"<Data a=\"a\" b=\"b\" c=\"c\" d=\"d\"><Date runDt=\"01-01-1900\" /></Data>\n" +
"<Data a=\"a\" b=\"b\" c=\"c\" d=\"d\"><Date runDt=\"01-01-1900\" /></Data>\n";
//xml can only contain one root tag. Need to wrap xml in root tag if one is missing
input = string.Format("<Root>{0}</Root>", input);
XDocument doc = XDocument.Parse(input);
// if loading from file
//string input = File.ReadAllText(filename);
//input = string.Format("<Root>{0}</Root>", input);
//XDocument doc = XDocument.Load(filename);
var results = doc.Descendants("Data").Select(x => new
{
a = x.Attribute("a").Value,
b = x.Attribute("b").Value,
c = x.Attribute("c").Value,
d = x.Attribute("d").Value,
date = DateTime.Parse(x.Element("Date").Attribute("runDt").Value)
}).ToList();
}
}
}