I have a problem, I can't get...and don't know what is wrong with it?
the code:
static void Main(string[] args)
{
XDocument doc = XDocument.Load(args[0] + "/?verb=GetRecord&metadataPrefix=p3dm&identifier=" + 1);
doc.Save("doc.xml");
var node = doc.Descendants("identifier");
foreach (var n in node)
{
doc.Save("file_" + n.Value + ".xml");
}
}
the doc.xml looks like:
<?xml version="1.0" encoding="utf-8"?>
<OAI-PMH xmlns="..." xmlns:xsi="..." xsi:schemaLocation="...">
<responseDate>...</responseDate>
<request verb="GetRecord" identifier="1"</request>
<GetRecord>
<record>
<header>
<identifier>1</identifier>
<datestamp>...</datestamp>
</header>
<metadata>
<P3DM xmlns="..." xsi:schemaLocation="...">
<MODELINFOID>1</MODELINFOID>
<TITLE>Roth</TITLE>
....
As we can see in doc.xml, there is element with the value 1, and using Descendants and foreach...I would like to save same document but using tag value to name my output file. What am I doing wrong. This code is just for testing.
Your XML has default namespace. You can use XNamespace plus element's local name to address an element in namespace :
......
//assume that the default namespace declared as <OAI-PMH xmlns="dummy.uri" ....>
XNamespace d = "dummy.uri";
var node = doc.Descendants(d+"identifier");
......
Related
I need to change ALL the Tag name to Lowercase but leave the InnerText or Value as it is. I just found the thread showing how to change the casing for the entire document but NOT just for the Tag names.
Code
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlDoc.OuterXml.ToLower());
Original.xml
<?xml version="1.0" encoding="utf-8" ?>
<ROOT>
<InNeRtAg>SoMe TeXt</InNeRtAg>
<NeStEdElEmEnT>
<InNeRnEsTiNg>SoMe TeXt</InNeRnEsTiNg>
</NeStEdElEmEnT>
</ROOT>
Changing ALL nodes including the root element:
var doc = XDocument.Load("Original.xml");
// also need to change the root element
doc.Root.Name = doc.Root.Name.LocalName.ToLower();
foreach (var element in doc.Descendants().Elements())
{
element.Name = element.Name.LocalName.ToLower();
}
doc.Save("Modified.xml");
Results in Modified.xml
<?xml version="1.0" encoding="utf-8"?>
<root>
<innertag>SoMe TeXt</innertag>
<nestedelement>
<innernesting>SoMe TeXt</innernesting>
</nestedelement>
</root>
When using
foreach (var element in doc.Descendants().Elements())
{
element.Name = element.Name.LocalName.ToLower();
}
the root element will not be changed.
<?xml version="1.0" encoding="utf-8"?>
<ROOT>
<innertag>SoMe TeXt</innertag>
<nestedelement>
<innernesting>SoMe TeXt</innernesting>
</nestedelement>
</ROOT>
You can try something like this:
var doc = XDocument.Load(filepath);
foreach (var element in doc.Descendants().Elements())
{
element.Name = element.Name.LocalName.ToLower();
}
my file XML:
<document xmlns="http://www.abbyy.com/FineReader_xml/FineReader10-schema-v1.xml" version="1.0" producer="ABBYY FineReader Engine 11" languages="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.abbyy.com/FineReader_xml/FineReader10-schema-v1.xml http://www.abbyy.com/FineReader_xml/FineReader10-schema-v1.xml">
<page width="1006" height="636" resolution="300" originalCoords="1" rotation="RotatedUpsidedown">
<block blockType="Text" blockName="" l="979" t="613" r="1006" b="636"><region><rect l="979" t="613" r="1006" b="636"/></region>
<text>
<par lineSpacing="890">
<line baseline="17" l="985" t="620" r="1006" b="636"><formatting lang="EnglishUnitedStates"><charParams l="985" t="620" r="1006" b="636" suspicious="1">r</charParams></formatting></line></par>
</text>
</block>
<block blockType="Barcode" blockName="" l="242" t="21" r="772" b="116"><region><rect l="242" t="21" r="772" b="116"/></region>
<text>
<par><line baseline="0" l="0" t="0" r="0" b="0"><formatting lang="">049102580225180310</formatting></line></par>
</text>
<barcodeInfo type="INTERLEAVED25"/>
</block>
</page>
</document>
I want extract number 049102580225180310 located in <formatting>..</formatting>
I try this code:
XElement racine = XElement.Load("test_XML.xml");
var query = from xx in racine.Elements(XName.Get("block"))
select new
{
CodeBar= xx.Attribute(XName.Get("formatting")).Value
};
But I haven't nothing
Here's a console program, that gets the 2nd formatting (where lang='') node.
using System;
using System.Xml;
namespace ConsoleApplication1 {
class Program {
static void Main(string[] args) {
XmlDocument xml = new XmlDocument();
xml.Load("c:\\temp\\test.xml");
NameTable nt = new NameTable();
XmlNamespaceManager nsmgr;
nsmgr = new XmlNamespaceManager(nt);
nsmgr.AddNamespace("html", xml.DocumentElement.NamespaceURI);
XmlNode ndFormat = xml.SelectSingleNode("//html:formatting[#lang='']", nsmgr);
if (ndFormat != null) {
Console.WriteLine(ndFormat.InnerText);
}
}
}
}
You have a couple issues here:
Your XML has a default namespace in the root node:
<document xmlns="http://www.abbyy.com/FineReader_xml/FineReader10-schema-v1.xml" version="1.0"
Thus all child elements are in this namespace, and so when querying for elements by their Name the appropriate namespace must be used when constructing an XName for which to search.
The <formatting> nodes are not direct children of the <block> nodes, they are nested within several levels of XML. Also, they are XML elements, not XML attributes.
Similarly the <block> elements are not direct children of the <document> root element, they are nested inside a <page> element.
In such cases XElement.Descendants(name) can be used to find nested elements by name.
Thus your query should be:
var ns = racine.Name.Namespace; // The root default namespace used by all the elements in the XML.
var query = from block in racine.Descendants(ns + "block")
from formatting in block.Descendants(ns + "formatting")
select new
{
CodeBar= (string)formatting,
};
Sample fiddle that outputs the values of the two <formatting> elements:
{ CodeBar = r }
{ CodeBar = 049102580225180310 }
XML example :
<?xml version="1.0" encoding="utf-8" ?>
<brand name="brand1" num_brand="118" enabled="True">
<price>
<nodePattern>pattern</nodePattern>
<attribute type="text" ></attribute>
<treatment enabled="1" type="Regex">reg</treatment>
</price>
<title>
<nodePattern>pattern</nodePattern>
<attribute type="text" ></attribute>
<treatment enabled="1" type="Regex">reg</treatment>
</title>
</brand>
Please, how can I get the different attributes values and text for all my different nodes (for example name, num_brand and enabled for brand, enabled, type and "reg" for treatment) using System.Xml.Linq ?
Thank you !
The System.Xml.Linq namespace is much nicer than the System.Xml namespace. Your XDocument has one XElement, which in turn has children elements. Each element has attributes and a value.
Here's an example for you:
var text = #"<?xml version=""1.0"" encoding=""utf-8"" ?>
<brand name=""brand1"" num_brand=""118"" enabled=""True"">
<price>
<nodePattern>pattern</nodePattern>
<attribute type=""text"" ></attribute>
<treatment enabled=""1"" type=""Regex"">reg</treatment>
</price>
<title>
<nodePattern>pattern</nodePattern>
<attribute type=""text"" ></attribute>
<treatment enabled=""1"" type=""Regex"">reg</treatment>
</title>
</brand>";
XDocument document = XDocument.Parse(text);
// one root element - "brand"
System.Diagnostics.Debug.Assert(document.Elements().Count() == 1);
XElement brand = document.Element("brand");
// brand has two children - price and title
foreach (var element in brand.Elements())
Console.WriteLine("element name: " + element.Name);
// brand has three attributes
foreach (var attr in brand.Attributes())
Console.WriteLine("attribute name: " + attr.Name + ", value: " + attr.Value);
You have many ways to do that. One of them is the XmlDocument.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(myXML);
foreach(XmlNode node in xmlDoc.DocumentElement.ChildNodes){
string text = node.InnerText; //you can loop through children
}
Take a look on this post :
How do I read and parse an XML file in C#?
Personnaly I like the Linq To Xml approach, more infos here :
https://msdn.microsoft.com/en-us/library/bb387061.aspx
try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENMAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENMAME);
var brand = doc.Descendants("brand").Select(x => new
{
name = x.Attribute("name").Value,
num_brand = x.Attribute("num_brand").Value,
enabled = x.Attribute("enabled").Value,
nodePattern = x.Element("price").Element("nodePattern").Value,
attribute = x.Element("price").Element("attribute").Attribute("type").Value,
priceTreatmentEnable = x.Element("price").Element("treatment").Attribute("enabled").Value,
priceTreatmentType = x.Element("price").Element("treatment").Attribute("type").Value,
priceTreatment = x.Element("price").Element("treatment").Value,
titleTreatmentEnable = x.Element("title").Element("treatment").Attribute("enabled").Value,
titleTreatmentType = x.Element("title").Element("treatment").Attribute("type").Value,
titleTreatment = x.Element("title").Element("treatment").Value
}).FirstOrDefault();
}
}
}
Using LINQ to XML.
I have an XML file which looks like this:
<?xml version="1.0" encoding="utf-8"?>
<TileMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Title>title</Title>
<Abstract>Some clever text about this.</Abstract>
<SRS>OSGEO:41001</SRS>
<Profile>global-mercator or something</Profile>
</TileMap>
I can retrieve the <Title> from this with no problems by using this little piece of code:
string xmlString = AppDomain.CurrentDomain.BaseDirectory + #"Capabilities\" + name + ".xml";
string xmlText = File.ReadAllText(xmlString);
byte[] buffer = Encoding.UTF8.GetBytes(xmlText);
XElement element = XElement.Load(xmlString);
IEnumerable<XElement> title =
from el in element.Elements("Title")
select el;
foreach (XElement el in title)
{
var elementValue = el.Value;
}
However, this isn't very flexible because say I have an XML file that looks like this:
<?xml version="1.0" encoding="utf-8"?>
<RootObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Services>
<TileMapService>
<Title>title</Title>
<href>http://localhost/root</href>
</TileMapService>
</Services>
</RootObject>
It can't find <Title> but it finds <Services> (I presume) but since it's not called "Title" it just ignores it. I'm not very strong in working with XML. How would I go about making a method that looks through the XML and fetches me "Title" or however you'd implement this?
You're currently just looking at the child elements of the root element.
Instead, if you want to find all descendants, use Descendants.
Additionally, there's no point in using a query expression of from x in y select x (or rather, there's a very limited point in some cases, but not here). So just use:
var titles = element.Descendants("Title");
Personally I would actually use XDocument here rather than XElement - you have after all got a whole document, complete with XML declaration, not just an element.
Change your LINQ query to:
IEnumerable<XElement> title =
from el in element.Descendants("Title")
select el;
Elements returns only the immediate children, Descendants returns all descendant nodes instead.
Descendants will select all the "Title" elements irrespective of the level. Please use xpath to correctly locate the element
using System;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using System.IO;
public class Program
{
public static void Main()
{
string xmlFile = AppDomain.CurrentDomain.BaseDirectory + #"Capabilities\" + name + ".xml";
XElement xml=XElement.Load(xmlFile);
IEnumerable<XElement> titleElements = xml.XPathSelectElements("//Services/TileMapService/Title");
}
}
I want to read the names form this xml:
<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://mysite.com/">
<name>2</name>
<name>3</name>
<name>4</name>
</string>
Tried:
var doc = XElement.Parse(s);
foreach (var v in doc.Descendants("name"))
{
//do work
}
but it does not work. Why?
Because you have a custom namespace - you need to specify the namespace when you select the elements - try this (tested and worked):
XNamespace xmlns = "http://mysite.com/";
var doc = XElement.Parse(s);
foreach (var v in doc.Descendants(xmlns + "name"))
{
//do work
}