c# XML transformation - c#

i need help for below xml. I wonder how can I bring the XML below, I've been trying for a very long time, but it didn't work. I would be grateful if you could help with this.
I can do the same thing in php, but since my data is a little big, php takes a lot of time, I read the file from the web service with c# and save it as xml, but it didn't work out as I wanted.
<ResultOfProductList xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ServerCode>kenan</ServerCode>
<ClientCode>B124565</ClientCode>
<Username>karanfil</Username>
<ClientIPAddress>78.135.235.3</ClientIPAddress>
<Successful>true</Successful>
<RequestDate>2022-07-22T12:28:54.6238843+03:00</RequestDate>
<ElapsedTimeMS>17</ElapsedTimeMS>
<MethodType>GetAllProductsByParts</MethodType>
<Result EndOfProducts="false">
<CustomerCode>B124565</CustomerCode>
<CustomerName>kenan</CustomerName>
<Date>2022-07-22T12:28:54.6238843+03:00</Date>
<Brands>
<Brand ID="174" Lang="tr" BrandName="PARTSMALL-KORE" StandardName=""/>
</Brands>
<Products>
<Product ID="134898" BrandID="174" ProductCode="KR-PML-PTA-086" ProducerCode="" MinOrderAmount="1" PiecesInBox="1" Unit="PCE" New="false">
<ProductNames>
<ProductName Lang="tr">VITES HALATI ( HYUNDAI : ACCENT 95-00 )</ProductName>
</ProductNames>
<BaseOeNr>43794-22000</BaseOeNr>
<Pricing>
<ListPriceCurrency>USD</ListPriceCurrency>
<LocalCurrency>TLY</LocalCurrency>
<CurrencyRate>17.6599</CurrencyRate>
<ListPriceWoVAT>31.24</ListPriceWoVAT>
<LocalListPriceWVat>651.0004</LocalListPriceWVat>
<LocalListPriceWoVat>551.695251</LocalListPriceWoVat>
<LocalNetPriceWVat>377.580261</LocalNetPriceWVat>
<LocalNetPriceWoVat>319.983246</LocalNetPriceWoVat>
<Discount1>42</Discount1>
<Discount2>0</Discount2>
<Discount3>0</Discount3>
<Discount4>0</Discount4>
<Discount5>0</Discount5>
<Discount6>0</Discount6>
<InDiscount>false</InDiscount>
</Pricing>
<Stocks>
<Stock WarehouseID="1" Equality="Eq">0</Stock>
<Stock WarehouseID="7" Equality="Eq">0</Stock>
<Stock WarehouseID="4" Equality="Eq">0</Stock>
<Stock WarehouseID="2" Equality="Eq">0</Stock>
<Stock WarehouseID="5" Equality="Eq">0</Stock>
</Stocks>
</Product>
</Result>
</ResultOfProductList>
Desired output
<Products>
<Product>
<ID>134898</ID>
<BrandID>174</BrandID>
<BaseOeNr>43794-22000</BaseOeNr>
<ProductCode>KR-PML-PTA-086</ProductCode>
<ProductName>VITES HALATI ( HYUNDAI : ACCENT 95-00 )</ProductName>
<LocalCurrency>TLY</LocalCurrency>
<LocalNetPriceWVat>377.580261</LocalNetPriceWVat>
<Stocks>WarehouseID=1 + WarehouseID=7 + WarehouseID=4 + WarehouseID=2 + WarehouseID=5 </Stocks>
</Product>
</Products>

Here is XSLT based solution.
It is just not clear if the <Stocks> element value is what you need.
Input XML
<?xml version="1.0"?>
<ResultOfProductList xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ServerCode>kenan</ServerCode>
<ClientCode>B124565</ClientCode>
<Username>karanfil</Username>
<ClientIPAddress>78.135.235.3</ClientIPAddress>
<Successful>true</Successful>
<RequestDate>2022-07-22T12:28:54.6238843+03:00</RequestDate>
<ElapsedTimeMS>17</ElapsedTimeMS>
<MethodType>GetAllProductsByParts</MethodType>
<Result EndOfProducts="false">
<CustomerCode>B124565</CustomerCode>
<CustomerName>kenan</CustomerName>
<Date>2022-07-22T12:28:54.6238843+03:00</Date>
<Brands>
<Brand ID="174" Lang="tr" BrandName="PARTSMALL-KORE" StandardName=""/>
</Brands>
<Products>
<Product ID="134898" BrandID="174" ProductCode="KR-PML-PTA-086" ProducerCode="" MinOrderAmount="1" PiecesInBox="1" Unit="PCE" New="false">
<ProductNames>
<ProductName Lang="tr">VITES HALATI ( HYUNDAI : ACCENT 95-00 )</ProductName>
</ProductNames>
<BaseOeNr>43794-22000</BaseOeNr>
<Pricing>
<ListPriceCurrency>USD</ListPriceCurrency>
<LocalCurrency>TLY</LocalCurrency>
<CurrencyRate>17.6599</CurrencyRate>
<ListPriceWoVAT>31.24</ListPriceWoVAT>
<LocalListPriceWVat>651.0004</LocalListPriceWVat>
<LocalListPriceWoVat>551.695251</LocalListPriceWoVat>
<LocalNetPriceWVat>377.580261</LocalNetPriceWVat>
<LocalNetPriceWoVat>319.983246</LocalNetPriceWoVat>
<Discount1>42</Discount1>
<Discount2>0</Discount2>
<Discount3>0</Discount3>
<Discount4>0</Discount4>
<Discount5>0</Discount5>
<Discount6>0</Discount6>
<InDiscount>false</InDiscount>
</Pricing>
<Stocks>
<Stock WarehouseID="1" Equality="Eq">0</Stock>
<Stock WarehouseID="7" Equality="Eq">0</Stock>
<Stock WarehouseID="4" Equality="Eq">0</Stock>
<Stock WarehouseID="2" Equality="Eq">0</Stock>
<Stock WarehouseID="5" Equality="Eq">0</Stock>
</Stocks>
</Product>
</Products>
</Result>
</ResultOfProductList>
XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/ResultOfProductList">
<Products>
<xsl:for-each select="Result/Products/Product">
<xsl:variable name="BrandID" select="#BrandID"/>
<Product>
<ID>
<xsl:value-of select="#ID"/>
</ID>
<!--<BrandID>
<xsl:value-of select="#BrandID"/>
</BrandID>-->
<BrandName><xsl:value-of select="../../Brands/Brand[#ID=$BrandID]/#BrandName"/></BrandName>
<BaseOeNr>
<xsl:value-of select="BaseOeNr"/>
</BaseOeNr>
<ProductCode>
<xsl:value-of select="#ProductCode"/>
</ProductCode>
<ProductName>
<xsl:value-of select="ProductNames/ProductName"/>
</ProductName>
<LocalCurrency>
<xsl:value-of select="Pricing/LocalCurrency"/>
</LocalCurrency>
<LocalNetPriceWVat>
<xsl:value-of select="Pricing/LocalNetPriceWVat"/>
</LocalNetPriceWVat>
<Stocks><xsl:value-of select="sum(Stocks/Stock)"/></Stocks>
</Product>
</xsl:for-each>
</Products>
</xsl:template>
</xsl:stylesheet>
Output XML
<Products>
<Product>
<ID>134898</ID>
<BrandName>PARTSMALL-KORE</BrandName>
<BaseOeNr>43794-22000</BaseOeNr>
<ProductCode>KR-PML-PTA-086</ProductCode>
<ProductName>VITES HALATI ( HYUNDAI : ACCENT 95-00 )</ProductName>
<LocalCurrency>TLY</LocalCurrency>
<LocalNetPriceWVat>377.580261</LocalNetPriceWVat>
<Stocks>0</Stocks>
</Product>
</Products>
c#
void Main()
{
const string SOURCEXMLFILE = #"e:\Temp\input.xml";
const string XSLTFILE = #"e:\Temp\process.xslt";
const string OUTPUTXMLFILE = #"e:\temp\output.xml";
try
{
XsltArgumentList xslArg = new XsltArgumentList();
using (XmlReader src = XmlReader.Create(SOURCEXMLFILE))
{
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(XSLTFILE, new XsltSettings(true, true), new XmlUrlResolver());
XmlWriterSettings settings = xslt.OutputSettings.Clone();
settings.IndentChars = "\t";
// to remove BOM
settings.Encoding = new UTF8Encoding(false);
using (XmlWriter result = XmlWriter.Create(OUTPUTXMLFILE, settings))
{
xslt.Transform(src, xslArg, result, new XmlUrlResolver());
result.Close();
}
}
Console.WriteLine("File '{0}' has been generated.", OUTPUTXMLFILE);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

Related

Using C# to copy different nodes from two files and pasting it on a third one

I have a task that is very cumbersome, as I have to do it by hand (my company bought a tool for a ludicrous amount of money that doesn't work anymore).
I have two XML lists, each of them has half of it missing, so I need to piece it together into a third one before sending it to the system. As well as changing the header to the date I'm sending the file.
I've managed to set up the input for the date, it's easy enough to ask the user for the input. But the rest of the task is driving me mad, I tried many things I've found around here and on the Microsoft forums, to no avail... this task is killing me because I'm the only one that is "tech savvy" to do it (it's literally monkey job of copying and pasting text from XMLs).
It's not trucks and cars, obviously, and there are more files than two, but they all are like this: one kind has only cars, with an empty truck node, and the other has trucks but with empty cars node.
Example of File 1
<?xml version="1.0" encoding="utf-8"?>
<document>
<header>
<startDate>01/01/2020</startDate>
<endDate>01/02/2020</endDate>
</header>
<body>
<cars>
<car>
<ID>1</ID>
<Name>Blue Car</Name>
</car>
<car>
<ID>2</ID>
<Name>Red Car</Name>
</car>
</cars>
<trucks>
</trucks>
</body>
</document>
Example of File 2
<?xml version="1.0" encoding="utf-8"?>
<document>
<header>
<startDate>01/01/2020</startDate>
<endDate>01/02/2020</endDate>
</header>
<body>
<cars>
</cars>
<trucks>
<truck>
<ID>1</ID>
<Name>Blue Truck</Name>
</truck>
<truck>
<ID>2</ID>
<Name>Red Truck</Name>
</truck>
</trucks>
</body>
</document>
Example of File 3
<?xml version="1.0" encoding="utf-8"?>
<document>
<header>
<Date>03/02/2020</Date>
</header>
<body>
<cars>
<car>
<ID>1</ID>
<Name>Blue Car</Name>
</car>
<car>
<ID>2</ID>
<Name>Red Car</Name>
</car>
</cars>
<trucks>
<truck>
<ID>1</ID>
<Name>Blue Truck</Name>
</truck>
<truck>
<ID>2</ID>
<Name>Red Truck</Name>
</truck>
</trucks>
</body>
</document>
Use XSLT:
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="*">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>
<xsl:template match="cars">
<cars>
<xsl:copy-of select="car"/>
<xsl:copy-of select="document('other-doc.xml')//car"/>
</cars>
</xsl:template>
<xsl:template match="trucks">
<trucks>
<xsl:copy-of select="truck"/>
<xsl:copy-of select="document('other-doc.xml')//truck"/>
</trucks>
</xsl:template>
</xsl:transform>
This can of course be run very easily using from C# using the System.Xml.Xsl processor.
I haven't tried to do anything with the dates in the header because I'm not sure what your logic is, but that's easily added.
If you want to use a later version of XSLT it becomes a little shorter but then you need to install a third-party library:
<xsl:transform version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="cars">
<cars>
<xsl:copy-of select="car, doc('other-doc.xml')//car"/>
</cars>
</xsl:template>
<xsl:template match="trucks">
<trucks>
<xsl:copy-of select="truck, doc('other-doc.xml')//truck"/>
</trucks>
</xsl:template>
</xsl:transform>
Please use below code
string xml1 = #"<document><header><startDate>01/01/2020</startDate><endDate> 01/02/ 2020</endDate></header><body><cars><car><ID>1</ID><Name>Blue Car</Name></car><car><ID>2</ID><Name>Red Car</Name></car></cars><trucks></trucks></body></document>";
//load xml in StringReader
StringReader sr = new StringReader(xml1);
DataSet ds1 = new DataSet();
// Read XML in ds1
ds1.ReadXml(sr);
string xml2 = #"<document><header><startDate> 01 / 01 / 2020 </startDate><endDate> 01 / 02 / 2020</endDate></header><body><cars></cars><trucks><truck><ID> 1 </ID><Name> Blue Truck </Name></truck><truck><ID>2</ID><Name>Red Truck</Name></truck></trucks></body></document>";
sr = new StringReader(xml2);
DataSet ds2 = new DataSet();
ds2.ReadXml(sr);
DataSet dsHeaders = new DataSet();
dsHeaders.Tables.Add(ds1.Tables[0].Copy());
string headersXML = dsHeaders.GetXml();
headersXML = headersXML.Replace("<NewDataSet>", "").Replace("</NewDataSet>", "");
// Console.WriteLine(headersXML.Trim());
DataSet dsCars = new DataSet("Cars");
dsCars.Tables.Add(ds1.Tables[3].Copy());
string carsXML = dsCars.GetXml();
// Console.WriteLine(carsXML);
DataSet dsTrucks = new DataSet("Trucks");
dsTrucks.Tables.Add(ds2.Tables[3].Copy());
string trucksXML = dsTrucks.GetXml();
// Console.WriteLine(trucksXML);
string resultXML = #"<document>" + headersXML + "<body>" + Environment.NewLine + carsXML + trucksXML + Environment.NewLine + "</body>" + Environment.NewLine + "</document>";
Console.WriteLine(resultXML);
Your required XML
<document>
<header>
<startDate>01/01/2020</startDate>
<endDate> 01/02/ 2020</endDate>
</header>
<body>
<Cars>
<car>
<ID>1</ID>
<Name>Blue Car</Name>
</car>
<car>
<ID>2</ID>
<Name>Red Car</Name>
</car>
</Cars><Trucks>
<truck>
<ID> 1 </ID>
<Name> Blue Truck </Name>
</truck>
<truck>
<ID>2</ID>
<Name>Red Truck</Name>
</truck>
</Trucks>
</body>
</document>
Using xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication2
{
class Program
{
const string FILE1 = #"c:\TEMP\TEST.XML";
const string FILE2 = #"c:\TEMP\TEST1.XML";
static void Main(string[] args)
{
string xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><document></document>";
XDocument doc3 = XDocument.Parse(xml);
XElement doc = doc3.Root;
doc.Add(new XElement("header", new XElement("Date", DateTime.Now.ToString("mm/dd/yyyy"))));
XDocument doc1 = XDocument.Load(FILE1);
XDocument doc2 = XDocument.Load(FILE2);
XElement body = new XElement("body");
doc.Add(body);
XElement cars = new XElement("cars");
body.Add(cars);
List<XElement> cars1 = doc1.Descendants("car").ToList();
cars.Add(cars1);
List<XElement> cars2 = doc2.Descendants("car").ToList();
cars.Add(cars2);
XElement trucks = new XElement("trucks");
body.Add(trucks);
List<XElement> trucks1 = doc1.Descendants("truck").ToList();
trucks.Add(trucks1);
List<XElement> trucks2 = doc2.Descendants("truck").ToList();
trucks.Add(trucks2);
}
}
}

XSLT: Howto output '<' and '>' from XSL transformation?

I am building some text snippets from XML documents using XSL transformation. The text can include '<' and '>' (and other special characters) in the output.
Given the following xml as data.xml:
<SCH>
<Ship Id="1" Name="Dicke Bertha" OperatingCostsDay="10.0000000" currency="USD" />
</SCH>
and the following xsl as transformation.xslt
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:template match="/">
Schiff: <xsl:for-each select="SCH/Ship"> Id: <xsl:value-of select="#Id"/>  <xsl:value-of select="#Name"/>  (OC:<xsl:value-of select="#OperatingCostsDay"/> <xsl:value-of select="#currency"/>)
</xsl:for-each>Betriebskosten < 500 USD oder > 1 Mio. USD
</xsl:template>
</xsl:stylesheet>
I have the problem that the escape sequences < and > when loading the XSLT:
var xslDocument = XDocument.Load("transformation.xslt");
The output after the transformation is not - as expected - with the '<' and '>' characters but it has the HTML escape sequences.
Schiff: Id: 1  Dicke Bertha  (OC:10.0000000 USD)
Betriebskosten < 500 USD oder > 1 Mio. USD
What can I do here?
For completeness, here is the full code example:
class Program
{
static void Main(string[] args)
{
var xslDocument = XDocument.Load("transformation.xslt");
var compiled = new XslCompiledTransform();
using (var reader = xslDocument.CreateReader())
{
compiled.Load(reader);
}
var xml = File.ReadAllText("data.xml");
Console.WriteLine(Transform(compiled, xml));
}
public static string Transform(XslCompiledTransform xsl, string xml)
{
// allow fragments
var writerSettings = new XmlWriterSettings { ConformanceLevel = ConformanceLevel.Auto };
var readerSettings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Auto };
var stringReader = new StringReader(xml);
var details = new StringBuilder();
using (var reader = XmlReader.Create(stringReader, readerSettings))
{
using (var writer = XmlWriter.Create(details, writerSettings))
{
xsl.Transform(reader, writer);
}
}
return details.ToString();
}
}
I am building some text snippets
If you are outputting text, then set your output method to text. Then your processor will know not to escape characters that are reserved in XML.
XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8" />
<xsl:template match="/">
Schiff: <xsl:for-each select="SCH/Ship"> Id: <xsl:value-of select="#Id"/>  <xsl:value-of select="#Name"/>  (OC:<xsl:value-of select="#OperatingCostsDay"/> <xsl:value-of select="#currency"/>)
</xsl:for-each>Betriebskosten < 500 USD oder > 1 Mio. USD
</xsl:template>
</xsl:stylesheet>
Result:
Schiff: Id: 1  Dicke Bertha  (OC:10.0000000 USD)
Betriebskosten < 500 USD oder > 1 Mio. USD
Note also that literal text is best put inside xsl:text instructions - otherwise you're passing all the unwanted surrounding whitespace to the output.
in XSLT, you can try like
Here I have added <xsl:text disable-output-escaping="yes"><</xsl:text> and <xsl:text disable-output-escaping="yes">></xsl:text>
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:template match="/">
Schiff: <xsl:for-each select="SCH/Ship"> Id: <xsl:value-of select="#Id"/>  <xsl:value-of select="#Name"/>  (OC:<xsl:value-of select="#OperatingCostsDay"/> <xsl:value-of select="#currency"/>)
</xsl:for-each> Betriebskosten <xsl:text disable-output-escaping="yes"><</xsl:text> 500 USD oder <xsl:text disable-output-escaping="yes">></xsl:text> 1 Mio. USD
</xsl:template>
</xsl:stylesheet>

How to pass document type parameter to xslt using saxon?

For sending atomic data types will use like
transformer.SetParameter(new QName("", "", customXml), new XdmAtomicValue("true"));
how to pass a XML/Node as a param to XSLT from C# ?
Can you please help me
followed your code it's working fine but i am getting only text inside the xml(what i am passing in parameter) but not Nodes
XSLT :
<xsl:param name="look-up" as="document-node()"/>
<xsl:template match="xpp:document">
<w:document xml:space="preserve">
<xsl:value-of select="$look-up"/>
</w:document>
</xsl:template>
XML
<?xml version="1.0" encoding="UTF-8"?>
<document version="1.0" xmlns="http://www.sdl.com/xpp">
//some tags
</document>
passing parameter (xml)
<Job>
</id>
</Job>
I think you should use the Processor object to construct an XdmNode, see the documentation which says:
The Processor provides a method NewDocumentBuilder which, as the name
implies, returns a DocumentBuilder. This may be used to construct a
document (specifically, an XdmNode) from a variety of sources. The
input can come from raw lexical XML by specifying a Stream or a Uri,
or it may come from a DOM document built using the Microsoft XML
parser by specifying an XmlNode, or it may be supplied
programmatically by nominating an XmlReader.
Then you can pass in the XdmNode to the SetParameter method http://saxonica.com/documentation/html/dotnetdoc/Saxon/Api/XsltTransformer.html#SetParameter%28Saxon.Api.QName,Saxon.Api.XdmValue%29 as XdmValue is a base class of XdmNode (XmlValue -> XdmItem -> XdmNode).
Here is an example that works for me with Saxon 9.5 HE on .NET:
Processor proc = new Processor();
DocumentBuilder db = proc.NewDocumentBuilder();
XsltTransformer trans;
using (XmlReader xr = XmlReader.Create("../../XSLTFile1.xslt"))
{
trans = proc.NewXsltCompiler().Compile(xr).Load();
}
XdmNode input, lookup;
using (XmlReader xr = XmlReader.Create("../../XMLFile1.xml"))
{
input = db.Build(xr);
}
using (XmlReader xr = XmlReader.Create("../../XMLFile2.xml"))
{
lookup = db.Build(xr);
}
trans.InitialContextNode = input;
trans.SetParameter(new QName("lookup-doc"), lookup);
using (XmlWriter xw = XmlWriter.Create(Console.Out))
{
trans.Run(new TextWriterDestination(xw));
}
The XSLT is
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:param name="lookup-doc"/>
<xsl:key name="map" match="map" use="key"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="item">
<xsl:copy>
<xsl:value-of select="key('map', ., $lookup-doc)/value"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
the XML documents are
<root>
<item>foo</item>
</root>
and
<root>
<map>
<key>foo</key>
<value>bar</value>
</map>
</root>
the resulting output is
<root>
<item>bar</item>
</root>

Xml for txt file records

I am having a scenario to push the text records to db to track some information on an individual.
My text file contains the data as shown below:
logonID|agentName|modify|exception|start|stop|externalID
14051286759|Jacks, Monica|1373477063|Break|01:45|02:00|USWMAJ43
14051286759|Jacks, Monica|1373477063|Break|06:10|06:25|USWMAJ43
14051286759|Jacks, Monica|1373477063|Lunch|03:45|04:30|USWMAJ43
14051286759|Jacks, Monica|1373477063|Open|00:00|01:45|USWMAJ43
14051286759|Jacks, Monica|1373477063|Open|02:00|03:45|USWMAJ43
14051286759|Jacks, Monica|1373477063|Open|04:30|06:10|USWMAJ43
14051286759|Jacks, Monica|1373477063|Open|06:25|08:30|USWMAJ43
Now i need to create an XML for Break,Lunch and open(number of open for a record may vary about 5 to 6 entries) as:
<info>
<break>
<break_1>01:45-02:00</break_1>
<break_2>06:10-06:25</break_1>
</break>
<lunch>03:45-04:30</lunch>
<open>
<open_1>00:00-01:45</open_1>
<open_2>02:00-03:45</open_2>
<open_3>04:30-06:10</open_3>
<open_4>06:25-08:30</open_4>
</open>
</info>
Thanks in Advance
XSLT
To use the xslt you pass the file location to pText parameter, for example file:///C:/data.txt :
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pText" />
<xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:variable name="vText" select="unparsed-text($pText)"/>
<xsl:variable name="vLines" select="tokenize($vText, '\r?\n')[position() > 1][normalize-space()]"/>
<xsl:template match="/">
<info>
<xsl:for-each-group select="$vLines" group-by="tokenize(.,'\|')[4]">
<xsl:variable name="vKey" select="translate(current-grouping-key(), $uppercase, $smallcase)"/>
<xsl:element name="{$vKey}">
<xsl:for-each select="current-group()">
<xsl:variable name="vValues" select="tokenize(.,'\|')"/>
<xsl:variable name="vPos" select="position()"/>
<xsl:element name="{$vKey}_{$vPos}">
<xsl:value-of select="concat($vValues[5],'-',$vValues[6])"/>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:for-each-group>
</info>
</xsl:template>
</xsl:stylesheet>
Input:
logonID|agentName|modify|exception|start|stop|externalID
14051286759|Jacks, Monica|1373477063|Break|01:45|02:00|USWMAJ43
14051286759|Jacks, Monica|1373477063|Break|06:10|06:25|USWMAJ43
14051286759|Jacks, Monica|1373477063|Lunch|03:45|04:30|USWMAJ43
14051286759|Jacks, Monica|1373477063|Open|00:00|01:45|USWMAJ43
14051286759|Jacks, Monica|1373477063|Open|02:00|03:45|USWMAJ43
14051286759|Jacks, Monica|1373477063|Open|04:30|06:10|USWMAJ43
14051286759|Jacks, Monica|1373477063|Open|06:25|08:30|USWMAJ43
Output:
<info>
<break>
<break_1>01:45-02:00</break_1>
<break_2>06:10-06:25</break_2>
</break>
<lunch>
<lunch_1>03:45-04:30</lunch_1>
</lunch>
<open>
<open_1>00:00-01:45</open_1>
<open_2>02:00-03:45</open_2>
<open_3>04:30-06:10</open_3>
<open_4>06:25-08:30</open_4>
</open>
</info>
C#
Reference 1 and Reference 2
XsltArgumentList argsList = new XsltArgumentList();
argsList.AddParam("pText", "", "file:///C:/data.txt");
XPathDocument myXPathDoc = new XPathDocument(myXmlFile) ;
XslCompiledTransform myXslTrans = new XslCompiledTransform();
myXslTrans.Load(myStyleSheet);
XmlTextWriter myWriter = new XmlTextWriter("result.html",null);
myXslTrans.Transform(myXPathDoc,argsList,myWriter);

How can I transform XML to invalid XML using XSLT?

I need to transform a valid XML document to the OFX v1.0.2 format. This format is more or less XML, but it's technically invalid and therefore cannot be parsed as XML.
I'm having trouble getting my Xml transformation working because the .Net XslCompiledTransform object insists on interpreting the output as an XML document (which is fair enough).
**Here's my function to transform the Xml
public string Transform(XmlElement xmlElement, Dictionary<string, object> parameters)
{
string strReturn = "";
// Set the settings to allow scripts to executed.
XsltSettings settings = new XsltSettings(false, true);
// Load the XSLT Document
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(xsltFileName, settings, new XmlUrlResolver());
// arguments
XsltArgumentList args = new XsltArgumentList();
if (parameters != null && parameters.Count > 0)
{
foreach (string key in parameters.Keys)
{
args.AddParam(key, "", parameters[key]);
}
}
//Create a memory stream to write to
Stream objStream = new MemoryStream();
// Transform the xml/xslt into a Writer
XmlTextWriter xmlWriter = new XmlTextWriter(objStream, Encoding.UTF8);
// Apply the transform
xslt.Transform(xmlElement, args, xmlWriter);
objStream.Seek(0, SeekOrigin.Begin);
// Read the contents of the stream
StreamReader objSR = new StreamReader(objStream);
strReturn = objSR.ReadToEnd();
return strReturn;
}
If I escape the xml-ish tags using < and &gt, they get removed when I download the file.
Here's the start of my XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"></xsl:output>
<xsl:param name="currentdate"></xsl:param>
<xsl:template match="Transactions">
OFXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
<OFX>
<SIGNONMSGSRSV1>
<SONRS>
<STATUS>
<CODE>0
<SEVERITY>INFO
</STATUS>
<DTSERVER><xsl:value-of select="$currentdate" />
<LANGUAGE>ENG
So can I transform my XML to a plain text string?
UPDATE:
I've changed this question. I just realised the obvious answer to the original question. Using the XslCompiledTransform object requires me to write the output to an Xml document using an XmlTextWriter. Obviously it won't parse. Apologies.
Xslt can output text; just make sure that you set the output-mode of the xslt to text, and wriet to a TextWriter (there are multiple overloads available). Writing something that is nearly xml in xslt is painful, but possible with disabling the escape rules.
Here's an example (albeit ugly) xslt for writing non-xml:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="text" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:call-template name="startElement">
<xsl:with-param name="name" select="'SONRS'"/>
</xsl:call-template>
<xsl:call-template name="startElement">
<xsl:with-param name="name" select="'STATUS'"/>
<xsl:with-param name="value" select="0"/>
</xsl:call-template>
<xsl:call-template name="startElement">
<xsl:with-param name="name" select="'SEVERITY'"/>
<xsl:with-param name="value" select="'INFO'"/>
</xsl:call-template>
<xsl:call-template name="endElement">
<xsl:with-param name="name" select="'SONRS'"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="startElement">
<xsl:param name="name"/>
<xsl:param name="value"/>
<xsl:text disable-output-escaping="yes"><</xsl:text>
<xsl:value-of select="$name"/>
<xsl:text disable-output-escaping="yes">></xsl:text>
<xsl:value-of select="$value"/>
</xsl:template>
<xsl:template name="endElement">
<xsl:param name="name"/>
<xsl:text disable-output-escaping="yes"></</xsl:text>
<xsl:value-of select="$name"/>
<xsl:text disable-output-escaping="yes">></xsl:text>
</xsl:template>
</xsl:stylesheet>

Categories

Resources