C#-XML-压缩 [英] C# - XML - Compression
问题描述
我遇到一种情况,我正在生成要提交给Web服务的XML文件,有时是由于其数据量超过30mb或50mb.
I have a situation where I am generating a XML file to be submitted to a webservice, sometimes due to the amount of data it exceeds 30mb or 50mb.
我需要使用c#、. net framework 4.0压缩文件,而不是具有大部分数据的节点之一..我不知道我要怎么做..如果有人可以请给我一个例子,说明如何完成此工作.
I need to compress the file, using c#, .net framework 4.0, rather one of the nodes which has most of the data.. I have no idea how i am going to do it .. is it possible if someone can give me a example of how I can get this done please.
xml文件如下所示
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<HeaderTalk xmlns="http://www.w3schools.com/xml">
<EnvelopeVersion>2.0</EnvelopeVersion>
<Header>
<MessageDetails>
<Class>CHAR-CLM</Class>
</MessageDetails>
<SenderDetails>
<IDAuthentication>
<SenderID>aaaaaa</SenderID>
<Authentication>
<Method>MD5</Method>
<Role>principal</Role>
<Value>a3MweCsv60kkAgzEpXeCqQ==</Value>
</Authentication>
</IDAuthentication>
<EmailAddress>Someone@somewhere.com</EmailAddress>
</SenderDetails>
</Header>
<TalkDetails>
<ChannelRouting>
<Channel>
<URI>1953</URI>
<Product>My product</Product>
<Version>2.0</Version>
</Channel>
</ChannelRouting>
</TalkDetails>
<Body>
<envelope xmlns="http://www.w3schools.com/xml/">
<PeriodEnd>2013-08-13</PeriodEnd>
<IRmark Type="generic">zZrxvJ7JmMNaOyrMs9ZOaRuihkg=</IRmark>
<Sender>Individual</Sender>
<Report>
<AuthOfficial>
<OffName>
<Fore>B</Fore>
<Sur>M</Sur>
</OffName>
<Phone>0123412345</Phone>
</AuthOfficial>
<DefaultCurrency>GBP</DefaultCurrency>
<Claim>
<OrgName>B</OrgName>
<ref>AB12345</ref>
<Repayment>
<Account>
<Donor>
<Fore>Barry</Fore>
</Donor>
<Total>7.00</Total>
</Account>
<Account>
<Donor>
<Fore>Anthony</Fore>
</Donor>
<Total>20.00</Total>
</Account>
</Repayment>
</Claim>
</Report>
</envelope>
</Body>
</HeaderTalk>
CLAIM节点是我要压缩的对象,因为它可能是数百万条包含在XML中的记录.
The CLAIM node is what I want to Compress , as it can be Millions of records that get included in the XML.
我是编码的新手,我花了很长时间才能生成此XML,并且一直在寻找找到一种压缩节点的方法,但是我无法使其工作.直到DefaultCurrency节点为止,结果必须完全相同.然后
I am a novice in coding, it has taken a long time for me to get this XML generated, and been searching to find a way to compress the node but I just cant get it to work.. the Result needs to be exactly same till the DefaultCurrency node.. and then
</AuthOfficial>
<DefaultCurrency>GBP</DefaultCurrency>
<CompressedPart Type="zip">UEsDBBQAAAAIAFt690K1</CompressedPart>
</Report>
</envelope>
</Body>
</HeaderTalk>
或
</AuthOfficial>
<DefaultCurrency>GBP</DefaultCurrency>
<CompressedPart Type="gzip">UEsDBBQAAAAIAFt690K1</CompressedPart>
</Report>
</envelope>
</Body>
</HeaderTalk>
请先谢谢大家.或者,如果有人可以建议我可以看的地方并获得一些想法,请问我想做什么.
Thank you everyone in advance please. Or if someone can suggest where I can look and get some idea, on what I want to do.
要创建文件,我可以简单地遍历数据集并使用XmlElements编写节点并将内部文本设置为值..
to create the file , I am simple iterating through a Dataset and Writing the nodes using XmlElements and setting innertexts to my values ..
我以前编写的代码是..//声明
The Code I have used to write is .. //claim
XmlElement GovtSenderClaim = xmldoc.CreateElement("Claim");
XmlElement GovtSenderOrgname = xmldoc.CreateElement("OrgName");
GovtSenderOrgname.InnerText = Charity_name;
GovtSenderClaim.AppendChild(GovtSenderOrgname);
XmlElement GovtSenderHMRCref = xmldoc.CreateElement("ref");
GovtSenderHMRCref.InnerText = strref ;
GovtSenderClaim.AppendChild(GovtSenderref);
XmlElement GovtSenderRepayments = xmldoc.CreateElement("Repayment");
while (reader.Read())
{
XmlElement GovtSenderAccount = xmldoc.CreateElement("Account");
XmlElement GovtSenderDonor = xmldoc.CreateElement("Donor");
XmlElement GovtSenderfore = xmldoc.CreateElement("Fore");
GovtSenderfore.InnerText = reader["EmployeeName_first_name"].ToString();
GovtSenderDonor.AppendChild(GovtSenderfore);
GovtSenderAccount .AppendChild(GovtSenderDonor);
XmlElement GovtSenderTotal = xmldoc.CreateElement("Total");
GovtSenderTotal.InnerText = reader["Total"].ToString();
GovtSenderAccount .AppendChild(GovtSenderTotal);
GovtSenderRepayments.AppendChild(GovtSenderAccount );
}
GovtSenderClaim.AppendChild(GovtSenderRepayments);
GovtSenderReport.AppendChild(GovtSenderClaim);
,其余节点关闭.
推荐答案
您可以尝试以下方法:它将仅压缩您选择的节点.它与您的要求有所不同,因为它将替换元素的 content ,而使元素及其属性保持原样.
You can try this: it will compress only the nodes you select. It's a little different from what you asked, because it will replace the content of the element, leaving the element + its attributes as they were.
{
// You are using a namespace!
XNamespace ns = "http://www.w3schools.com/xml/";
var xml2 = XDocument.Parse(xml);
// Compress
{
// Will compress all the XElement that are called Claim
// You should probably select the XElement in a better way
var nodes = from p in xml2.Descendants(ns + "Claim") select p;
foreach (XElement el in nodes)
{
CompressElementContent(el);
}
}
// Decompress
{
// Will decompress all the XElement that are called Claim
// You should probably select the XElement in a better way
var nodes = from p in xml2.Descendants(ns + "Claim") select p;
foreach (XElement el in nodes)
{
DecompressElementContent(el);
}
}
}
public static void CompressElementContent(XElement el)
{
string content;
using (var reader = el.CreateReader())
{
reader.MoveToContent();
content = reader.ReadInnerXml();
}
using (var ms = new MemoryStream())
{
using (DeflateStream defl = new DeflateStream(ms, CompressionMode.Compress))
{
// So that the BOM isn't written we use build manually the encoder.
// See for example http://stackoverflow.com/a/2437780/613130
// But note that false is implicit in the parameterless constructor
using (StreamWriter sw = new StreamWriter(defl, new UTF8Encoding()))
{
sw.Write(content);
}
}
string base64 = Convert.ToBase64String(ms.ToArray());
el.ReplaceAll(new XText(base64));
}
}
public static void DecompressElementContent(XElement el)
{
var reader = el.CreateReader();
reader.MoveToContent();
var content = reader.ReadInnerXml();
var bytes = Convert.FromBase64String(content);
using (var ms = new MemoryStream(bytes))
{
using (DeflateStream defl = new DeflateStream(ms, CompressionMode.Decompress))
{
using (StreamReader sr = new StreamReader(defl, Encoding.UTF8))
{
el.ReplaceAll(ParseXmlFragment(sr));
}
}
}
}
public static IEnumerable<XNode> ParseXmlFragment(StreamReader sr)
{
var settings = new XmlReaderSettings
{
ConformanceLevel = ConformanceLevel.Fragment
};
using (var xmlReader = XmlReader.Create(sr, settings))
{
xmlReader.MoveToContent();
while (xmlReader.ReadState != ReadState.EndOfFile)
{
yield return XNode.ReadFrom(xmlReader);
}
}
}
解压缩非常复杂,因为很难替换Xml的内容.最后,我用 ParseXmlFragment
中的 Xnode
和 DecompressElementContent
ReplaceAll 拆分了内容 XNode
>.
The decompress is quite complex, because it's difficult to replace the content of an Xml. In the end I split the content XNode
by Xnode
in ParseXmlFragment
and ReplaceAll
in DecompressElementContent
.
作为一个旁注,您的XML中有两个类似但不同的名称空间: http://www.w3schools.com/xml
和 http://www.w3schools.com/xml/
As a sidenote, you have two similar-but-different namespaces in you XML: http://www.w3schools.com/xml
and http://www.w3schools.com/xml/
此变体将完全按照您的要求进行操作(因此将创建一个CompressedPart节点),减去具有压缩类型的属性.
This other variant will do exactly what you asked (so it will create a CompressedPart node) minus the attribute with the type of compression.
{
XNamespace ns = "http://www.w3schools.com/xml/";
var xml2 = XDocument.Parse(xml);
// Compress
{
// Here the ToList() is necessary, because we will replace the selected elements
var nodes = (from p in xml2.Descendants(ns + "Claim") select p).ToList();
foreach (XElement el in nodes)
{
CompressElementContent(el);
}
}
// Decompress
{
// Here the ToList() is necessary, because we will replace the selected elements
var nodes = (from p in xml2.Descendants("CompressedPart") select p).ToList();
foreach (XElement el in nodes)
{
DecompressElementContent(el);
}
}
}
public static void CompressElementContent(XElement el)
{
string content = el.ToString();
using (var ms = new MemoryStream())
{
using (DeflateStream defl = new DeflateStream(ms, CompressionMode.Compress))
{
// So that the BOM isn't written we use build manually the encoder.
using (StreamWriter sw = new StreamWriter(defl, new UTF8Encoding()))
{
sw.Write(content);
}
}
string base64 = Convert.ToBase64String(ms.ToArray());
var newEl = new XElement("CompressedPart", new XText(base64));
el.ReplaceWith(newEl);
}
}
public static void DecompressElementContent(XElement el)
{
var reader = el.CreateReader();
reader.MoveToContent();
var content = reader.ReadInnerXml();
var bytes = Convert.FromBase64String(content);
using (var ms = new MemoryStream(bytes))
{
using (DeflateStream defl = new DeflateStream(ms, CompressionMode.Decompress))
{
using (StreamReader sr = new StreamReader(defl, Encoding.UTF8))
{
var newEl = XElement.Parse(sr.ReadToEnd());
el.ReplaceWith(newEl);
}
}
}
}
这篇关于C#-XML-压缩的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!