I have following SOAP response. Using my code I could only extract one element.
and then it throws null reference exception error.
How do I extract Item->key and Item->value in to my dictionary in the function in C#?
Following is a part of the function which i use to extract data from.
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP- ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:Magento" xmlns:ns2="http://xml.apache.org/xml-soap" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:callResponse>
<callReturn SOAP-ENC:arrayType="ns2:Map[2]" xsi:type="SOAP-ENC:Array">
<item xsi:type="ns2:Map">
<item>
<key xsi:type="xsd:string">state</key>
<value xsi:type="xsd:string">processing</value>
</item>
<item>
<key xsi:type="xsd:string">status</key>
<value xsi:type="xsd:string">processing</value>
</item>
<item>
<key xsi:type="xsd:string">protect_code</key>
<value xsi:type="xsd:string">ba8dd7</value>
</item>
<item>
<key xsi:type="xsd:string">shipping_firstname</key>
<value xsi:type="xsd:string">Roshan</value>
</item>
<item>
<key xsi:type="xsd:string">billing_name</key>
<value xsi:type="xsd:string">Roshan India</value>
</item>
<item>
<key xsi:type="xsd:string">shipping_name</key>
<value xsi:type="xsd:string">Roshan India</value>
</item>
<item>
<key xsi:type="xsd:string">order_id</key>
<value xsi:type="xsd:string">2</value>
</item>
</item>
</callReturn>
</ns1:callResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The codes,
try
{
XmlDocument xdoc = new XmlDocument();//xml doc used for xml parsing
xdoc.LoadXml(content); // --------> THIS IS WHERE I PASS SOAP RESPONSE
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xdoc.NameTable);
nsmgr.AddNamespace("SOAP-ENV:encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/");
XmlNodeList xNodelst = xdoc.DocumentElement.SelectNodes("//item");
int nodes = xNodelst.Count;
dynamic item;
Dictionary<string, string> items = new Dictionary<string, string>();
foreach (XmlNode xn in xNodelst)
{
XmlNode itemnode = xn["item"];
if (itemnode != null) {
string key = itemnode["key"].InnerText;
string value = itemnode["value"].InnerText;
items.Add(key, value);
}
}
var ss = items;
return "";
}
catch (Exception e) {
return e.Message;
}
The xml has two level of the tag item. So you have to make sure you treat each level of the item tag separately. I used xml linq to get data and put results into a dictionary.
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 FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement root = doc.Root;
XNamespace ns = root.GetDefaultNamespace();
XElement firstItem = doc.Descendants(ns + "item").FirstOrDefault();
Dictionary<string, string> dictItems = firstItem.Descendants(ns + "item")
.GroupBy(x => (string)x.Element("key"), y => (string)y.Element("value"))
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
}
}
}
I finally managed to make this work. I added all the namespaces in namespace manager variable. And used xPath to navigate through the XML as below,
XmlNodeList xNodelst = xdoc.DocumentElement.SelectNodes("//item[#xsi:type]",nsmgr);
This helped me to resolve my problem. I'm posting this here in case if anyone having similar issue.
Cheers!
string soapString = #"<soapenv:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:urn=""urn:Magento""><soapenv:Header/><soapenv:Body><urn:call soapenv:encodingStyle=""http://schemas.xmlsoap.org/soap/encoding/""><sessionId xsi:type=""xsd:string"">"+ssid +#"</sessionId><resourcePath xsi:type=""xsd:string"">sales_order.list</resourcePath><args xsi:type=""xsd:anyType""></args></urn:call></soapenv:Body></soapenv:Envelope>";
HttpResponseMessage response = await PostXmlRequest("http://localhost/M1/api.php", soapString);
string content = await response.Content.ReadAsStringAsync();
XmlDocument xdoc = new XmlDocument();//xml doc used for xml parsing
xdoc.LoadXml(content);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xdoc.NameTable);
nsmgr.AddNamespace("ns1", "urn:Magento");
nsmgr.AddNamespace("ns2", "http://xml.apache.org/xml-soap");
nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
nsmgr.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
nsmgr.AddNamespace("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/");
nsmgr.AddNamespace("encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/");
XmlNodeList xNodelst = xdoc.DocumentElement.SelectNodes("//item[#xsi:type]",nsmgr);
int nodes = xNodelst.Count;
Dictionary<int, IDictionary> items = new Dictionary<int, IDictionary>();
int n = 0;
foreach (XmlNode xn in xNodelst)
{
XmlNode itemnode = xn;
Dictionary<string, string> itemData = new Dictionary<string, string>();
foreach (XmlNode xn1 in itemnode)
{
string key = xn1["key"].InnerText;
string value = xn1["value"].InnerText;
itemData.Add(key, value);
}
items.Add(n, itemData);
n++;
}
return items;
Related
I'm trying to read values from following xml (which is previously fetched from FTP):
<?xml version="1.0" encoding="utf-8"?>
<eventdata xmlns="http://www.demoweb.net/xml/eventdata" >
<site>
<sitelink>demotesting</sitelink>
<user>15101991</user>
<measurement>
<nodelink>012019120312064500</nodelink>
<containername>A1</containername>
<time>2020-04-30T11:25:35</time>
<value type="n_v_unitvalue">0.04</value>
<value type="n_v_unitvalue_diff">0.040</value>
</measurement>
<measurement>
<nodelink>012019120312064501</nodelink>
<containername>A2</containername>
<time>2020-04-30T11:25:35</time>
<value type="n_v_unitvalue">0.0</value>
<value type="n_v_unitvalue_diff">-0.001</value>
</measurement>
<measurement>
<nodelink>012019120312064502</nodelink>
<containername>A3</containername>
<time>2020-04-30T11:25:34</time>
<value type="n_v_unitvalue">0.0</value>
<value type="n_v_unitvalue_diff">0.000</value>
</measurement>
</site>
<createdate>2020-04-30T11:25:35</createdate>
</eventdata>
Before I start, file is sucessfully loaded into memory :)
As you can see root node is eventdata, and site is the node where all data is contained.
So basically I need to loop all measurement nodes and get the data.
I also were struggling to get out user node.. here's what I've tried so far:
using (StreamReader xml_reader = new StreamReader(xml_response.GetResponseStream()))
{
string xml = xml_reader.ReadToEnd();
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(xml);
XmlNodeList mainFileContent = xmldoc.SelectNodes("eventdata");
// XmlNodeList mainFileContent = xmldoc.SelectNodes("eventdata/site");
XmlElement root = xmldoc.DocumentElement;
if (mainFileContent != null)
{
foreach (XmlNode node in mainFileContent)
{
var user = node["user"].InnerText;
}
}
}
What I'm missing?
THANKS GUYS
CHEERS
Your eventdata node has own xmlns declaration, you should properly handle it using XmlNamespaceManager and select the nodes with x:eventdata/x:site XPath expression
var xmldoc = new XmlDocument();
xmldoc.LoadXml(xml);
var nsmgr = new XmlNamespaceManager(xmldoc.NameTable);
nsmgr.AddNamespace("x", xmldoc.DocumentElement.NamespaceURI);
var mainFileContent = xmldoc.SelectNodes("x:eventdata/x:site", nsmgr);
foreach (XmlNode node in mainFileContent)
{
var user = node["user"]?.InnerText;
}
Use below code to read measurement
using (StreamReader xml_reader = new StreamReader(xml_response.GetResponseStream()))
{
string xml = xml_reader.ReadToEnd();
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(xml);
var nsmgr = new XmlNamespaceManager(xmldoc.NameTable);
nsmgr.AddNamespace("ns", "http://www.demoweb.net/xml/eventdata");
XmlNodeList mainFileContent = xmldoc.SelectNodes("ns:eventdata/ns:site",nsmgr);
XmlElement root = xmldoc.DocumentElement;
if (mainFileContent != null)
{
foreach (XmlNode site in mainFileContent)
{
var user = site["user"].InnerText;
XmlNodeList measurements = site.SelectNodes("ns:measurement", nsmgr);
if (measurements != null)
{
foreach (XmlNode measurement in measurements)
{
var containername = measurement["containername"].InnerText;
var time = measurement["time"].InnerText;
XmlNodeList values = measurement.SelectNodes("ns:value", nsmgr);
if (values != null)
{
foreach (XmlNode value in values)
{
var type = value.Attributes["type"].Value;
var v2 = value.InnerText;
}
}
}
}
}
}
}
I've created a program to retrieve data from a database and convert it to XML. It returns a list of 24 objects that I created:
<?xml version = "1.0" encoding = "utf-16"
<ArrayOfData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Data>
<interval>01</interval>
<num>12345</num>
<id>ABC123 </id>
<type>LETTER</type>
<party>1</party>
<amount>-10</amount>
</Data>
<Data>
<interval>02</interval>
<num>12345</num>
<id>ABC123 </id>
<type>LETTER</type>
<party>1</party>
<amount>-11</amount>
</Data>
<Data>
<interval>03</interval>
<num>12345</num>
<id>ABC123 </id>
<type>LETTER</type>
<party>1</party>
<amount>-12</amount>
</Data>
<Data>
<interval>04</interval>
<num>12345</num>
<id>ABC123 </id>
<type>LETTER</type>
<party>1</party>
<amount>-13</amount>
</Data>
Basically the data goes on with incrementing intervals by 1 up to 24.
What I am looking for is to look for what is duplicate and just concatenate them into one child, and then to look for what differs and create a different element for it but keep them everything in one child. How can I write the XML to do this? Example:
<Data>
<num>12345</num>
<id>ABC123 </id>
<type>LETTER</type>
<party>1</party>
<details>
<interval>01</interval>
<amount>-10</amount>
</details>
<details>
<interval>02</interval>
<amount>-11</amount>
</details>
<details>
<interval>03</interval>
<amount>-12</amount>
</details>
<details>
<interval>04</interval>
<amount>-13</amount>
</details>
</Data>
I want to create a function that returns this XML. The parameters in my current function now are just there to get the data using those parameters. Here's how I generate the XML now:
public IActionResult CreateXML(int num, int id)
{
string xml = "";
var temp = (from x in Context.InternalData.AsNoTracking() where (x.num == num && x.id == id) select x).ToList();
using (var stringwrite = new Utf8StringWriter())
{
var serializer = new XmlSerializer(temp.GetType());
serializer.Serialize(stringwrite, temp);
xml = stringwrite.ToString();
StringReader reader = new StringReader(stringwriter.ToString());
reader.ReadLine(); //skips the UTF-16 header
XDocument doc = XDocument.Load(reader);
XElement arrayOfData = doc.Root;
List<XElement> newData = new List<XElement>();
var parties = doc.Descendants("Data")
.GroupBy(x => (string)x.Element("id"))
.ToList();
foreach (var party in parties)
{
XElement template = party.First();
List<XElement> details = party.Select(x => new XElement("details", new object[] {
new XElement("interval", (string)x.Element("interval")),
new XElement("amount", (string)x.Element("amount"))
})).ToList();
template.Element("interval").Remove();
template.Element("amount").Remove();
template.Add(details);
newData.Add(template);
}
arrayOfData.ReplaceAll(newData);
return Ok(arrayOfData);
}
}
I am new to this and have never worked with generating XML before. Any help would be greatly appreciated!
Try xml linq :
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
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
string xml = File.ReadAllText(FILENAME);
StringWriter stringwriter = new StringWriter();
stringwriter.Write(xml);
StringReader reader = new StringReader(stringwriter.ToString());
reader.ReadLine(); //skips the UTF-16 header
XDocument doc = XDocument.Load(reader);
XElement arrayOfData = doc.Root;
List<XElement> newData = new List<XElement>();
var parties = doc.Descendants("Data")
.GroupBy(x => (string)x.Element("id"))
.ToList();
foreach (var party in parties)
{
XElement template = party.First();
List<XElement> details = party.Select(x => new XElement("details", new object[] {
new XElement("interval", (string)x.Element("interval")),
new XElement("amount", (string)x.Element("amount"))
})).ToList();
template.Element("interval").Remove();
template.Element("amount").Remove();
template.Add(details);
newData.Add(template);
}
arrayOfData.ReplaceAll(newData);
}
}
}
Can someone help me out with extracting the "Value Y" of 4.247 in this XML file. I've searched through previous threads but can't seem to apply them to this structure.
<Chart1>
<Chart1_SeriesGroup_Collection>
<Chart1_SeriesGroup Label="MP_Trend_Data\MP_Prog/MP_DAILY_FLOW">
<Chart1_CategoryGroup_Collection>
<Chart1_CategoryGroup Label="12/24/2017 1:58:19 AM">
<Value X="0001-01-01T10:30:00+10:30"/>
</Chart1_CategoryGroup>
<Chart1_CategoryGroup Label="12/24/2017 1:58:19 AM">
<Value X="0001-01-01T10:30:00+10:30"/>
</Chart1_CategoryGroup>
<Chart1_CategoryGroup Label="12/24/2017 1:59:19 AM">
<Value X="0001-01-01T10:30:00+10:30"/>
</Chart1_CategoryGroup>
<Chart1_CategoryGroup Label="12/24/2017 1:59:19 AM">
<Value X="0001-01-01T10:30:00+10:30"/>
</Chart1_CategoryGroup>
<Chart1_CategoryGroup Label="12/24/2017 1:58:19 AM">
<Value Y="4.24700021743774" X="2017-12-24T12:28:19.333+10:30"/>
</Chart1_CategoryGroup>
code I've tried:
var xDoc = XDocument.Load("C:\\attachment\\Flow.xml");
XmlDocument xml = new XmlDocument();
xml.LoadXml(xDoc.ToString());
XmlNodeList xnList = xml.SelectNodes("/Chart1/Chart1_SeriesGroup_Collection/Chart1_SeriesGroup[#Label='MP_Trend_Data\\MP_Prog/MP_DAILY_FLOW']");
foreach (XmlNode Node in xnList)
{
XmlNodeList ynList = Node.SelectNodes("/Chart1_CategoryGroup_Collection/Chart1_CategoryGroup/Value");
foreach (XmlNode Node2 in ynList)
{
textBox1.Text = Node2.Attributes["Y"].Value.ToString();
}
}
var xmlStr = #"
<Chart1>
<Chart1_SeriesGroup_Collection>
<Chart1_SeriesGroup Label='MP_Trend_Data\MP_Prog/MP_DAILY_FLOW'>
<Chart1_CategoryGroup_Collection>
<Chart1_CategoryGroup Label='12/24/2017 1:58:19 AM'>
<Value X='0001-01-01T10:30:00+10:30'/>
</Chart1_CategoryGroup>
<Chart1_CategoryGroup Label='12/24/2017 1:58:19 AM'>
<Value X='0001-01-01T10:30:00+10:30'/>
</Chart1_CategoryGroup>
<Chart1_CategoryGroup Label='12/24/2017 1:59:19 AM'>
<Value X='0001-01-01T10:30:00+10:30'/>
</Chart1_CategoryGroup>
<Chart1_CategoryGroup Label='12/24/2017 1:59:19 AM'>
<Value X='0001-01-01T10:30:00+10:30'/>
</Chart1_CategoryGroup>
<Chart1_CategoryGroup Label='12/24/2017 1:58:19 AM'>
<Value Y='4.24700021743774' X='2017-12-24T12:28:19.333+10:30'/>
</Chart1_CategoryGroup>
</Chart1_CategoryGroup_Collection>>
</Chart1_SeriesGroup>
</Chart1_SeriesGroup_Collection>
</Chart1>";
var xml = XElement.Parse(xmlStr);
var firstY = xml.Descendants("Value").FirstOrDefault(v => v.Attribute("Y") != null);
if (firstY != null)
{
var y = firstY.Attribute("Y").Value;
}
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
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var results = doc.Descendants("Chart1_CategoryGroup").Where(x => x.Element("Value").Attribute("Y") != null).Select(x => new {
label = (DateTime)x.Attribute("Label"),
y = (double)x.Element("Value").Attribute("Y"),
x = (DateTime)x.Element("Value").Attribute("X")
}).ToList();
}
}
}
I am trying to parse an XML response from a REST call. I can read the XML just fine with my stream reader but when I try to select the first node, it brings back nothing. Here is my XML:
<?xml version="1.0" encoding="UTF-8" standalone="true"?>
<slot_meta_data xmlns:ns2="http://www.w3.org/2005/Atom">
<product id="MDP">
<name>MDP</name>
</product>
<product id="CTxP">
<name>CTxP</name>
</product>
<product id="STR">
<name>STR</name>
</product>
<product id="ApP">
<name>ApP</name>
<slot>
<agent_id>-1111</agent_id>
<agent_name>ApP</agent_name>
<index_id>-1</index_id>
<alias>App Alias</slot_alias>
</slot>
</product>
<product id="TxP">
<name>TxP</name>
<slot>
<agent_id>2222</agent_id>
<agent_name>App2</agent_name>
<index_id>-1</index_id>
<alias>App2 Alias</slot_alias>
</slot>
</product>
</slot_meta_data>
Here is my code
string newURL = "RESTURL";
HttpWebRequest request = WebRequest.Create(newURL) as HttpWebRequest;
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
StreamReader reader = new StreamReader(response.GetResponseStream());
XmlDocument xdoc = new XmlDocument();
xdoc.Load(response.GetResponseStream());
XmlNodeList list = xdoc.SelectNodes("/slot_meta_data[#*]");
foreach (XmlNode node in list)
{
XmlNode product = node.SelectSingleNode("product");
string name = product["name"].InnerText;
string id = product["id"].InnerText;
Console.WriteLine(name);
Console.WriteLine(id);
Console.ReadLine();
}
When I debug list, it has a count of 0.
Using xml linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication22
{
class Program
{
const string FILENAME = #"c:\TEMP\TEST.XML";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var results = doc.Descendants("product").Select(x => new {
name = (string)x.Element("name"),
slot = x.Elements("slot").Select(y => new {
agent_id = (int)y.Element("agent_id"),
agent_name = (string)y.Element("agent_name"),
index_id = (int)y.Element("index_id"),
slot_alias = (string)y.Element("slot_alias")
}).FirstOrDefault()
}).ToList();
}
}
}
I m trying to strip my XML and keep only nodes which are in the String Keep array
Input XML is
<Employees>
<Employee>
<EmpId>1</EmpId>
<Name>Sam</Name>
<Sex>Male</Sex>
<Address>
<Country>USA</Country>
<Zip>95220</Zip>
</Address>
</Employee>
<Employee>
<EmpId>2</EmpId>
<Name>Lucy</Name>
<Sex>Female</Sex>
<Address>
<Country>USA</Country>
<Zip>95220</Zip>
</Address>
</Employee>
</Employees>
Output I need is
<Employees>
<Employee>
<EmpId>1</EmpId>
<Sex>Male</Sex>
<Address>
<Zip>95220</Zip>
</Address>
</Employee>
<Employee>
<EmpId>2</EmpId>
<Sex>Female</Sex>
<Address>
<Zip>95220</Zip>
</Address>
</Employee>
</Employees>
My code is as below.
private void button1_Click(object sender, EventArgs e)
{
XmlDocument xDoc = new XmlDocument();
xDoc.Load(XML_Path);
// xDoc.Load();
XmlNodeList xNodes = xDoc.SelectNodes("Employees/Employee");
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
doc.AppendChild(docNode);
XmlNode employeesNode = doc.CreateElement("Employees");
doc.AppendChild(employeesNode);
string s =null;
string keep = "EmpId,Sex,Address/Zip";
string[] strArr = keep.Split(',');
foreach(XmlNode xN in xNodes)
{
XmlNode employeeNode = doc.CreateElement("Employee");
employeesNode.AppendChild(employeeNode);
foreach (string str in strArr)
{
XmlNode xNod = xN.SelectSingleNode(str);
employeeNode.AppendChild(xNod);
}
}
richTextBox1.Text = doc.ToString();
}
I get a weird error in inner foreach loop it wont add the new node can anyone tell me what wrong am i doing.
Thanks
Try this using Linq to Xml, the code will be much succint.
private void button1_Click(object sender, EventArgs e)
{
var xDoc = XDocument.Load(XML_Path)
string keep = "EmpId,Sex,Address,Zip";
string[] strArr = keep.Split(',');
var nodesToDelete = xDoc.Root.Descendants("Employee")
.SelectMany(e => e.Descendants()
.Where(a => !strArr.Contains(a.Name.ToString())));
foreach (var node in nodesToDelete.ToList())
node.Remove();
richTextBox1.Text = xDoc.ToString();
}
How about using XDocument ?
Bellow code gives you the required output.
string xmlString =
#"<?xml version=""1.0""?>
<Employees>
<Employee>
<EmpId>1</EmpId>
<Name>Sam</Name>
<Sex>Male</Sex>
<Address>
<Country>USA</Country>
<Zip>95220</Zip>
</Address>
</Employee>
<Employee>
<EmpId>2</EmpId>
<Name>Lucy</Name>
<Sex>Female</Sex>
<Address>
<Country>USA</Country>
<Zip>95220</Zip>
</Address>
</Employee>
</Employees>
";
System.Xml.Linq.XDocument xmlDoc = System.Xml.Linq.XDocument.Parse(xmlString);
foreach (var employee in xmlDoc.Descendants("Employee"))
{
employee.Descendants("Name").First().Remove();
employee.Descendants("Address").First().Descendants("Country").First().Remove();
}
MessageBox.Show(xmlDoc.ToString());
You could go with something like this:
XmlDocument source = new XmlDocument();
source.LoadXml(xmldata);
var keep = new[] {"EmpId", "Sex", "Address/Zip"};
foreach (XmlElement employee in source.SelectNodes("/Employees/Employee"))
foreach (XmlElement child in employee.SelectNodes(".//*"))
{
if(keep.Any(i => i.StartsWith(child.Name) || i.EndsWith(child.Name)))
continue;
child.ParentNode.RemoveChild(child);
}
Console.WriteLine(source.OuterXml);
However, as your keep array could be changed and different scenarios could be required, you should try go with a XSLT transformation.