如何在 C# 中使用 XmlDsigC14NTransform 类
我正在尝试使用 c# .net Framework 2.0 的 System.Security.Cryptography.Xml.XMLDsigC14nTransform 类规范化 xml 节点。
该实例需要三种不同的输入类型:NodeList、Stream 和 XMLDocument。我尝试使用所有这些输入类型进行转换,但得到不同的结果。 我真正想做的是规范化单个节点,但正如您在输出文件中看到的那样,输出不包含任何内部 xml。
非常感谢任何有关规范化 XML 节点的正确方法的建议。 最好,
string path = @"D:\Test\xml imza\sign.xml";
XmlDocument xDoc = new XmlDocument();
xDoc.PreserveWhitespace = true;
using (FileStream fs = new FileStream(path, FileMode.Open))
{
xDoc.Load(fs);
}
// canon node list
XmlNodeList nodeList = xDoc.SelectNodes("//Child1");
XmlDsigC14NTransform transform = new XmlDsigC14NTransform();
transform.LoadInput(nodeList);
MemoryStream ms = (MemoryStream)transform.GetOutput(typeof(Stream));
File.WriteAllBytes(@"D:\Test\xml imza\child1.xml", ms.ToArray());
// canon XMLDocument
transform = new XmlDsigC14NTransform();
transform.LoadInput(xDoc);
ms = (MemoryStream)transform.GetOutput(typeof(Stream));
File.WriteAllBytes(@"D:\Test\xml imza\doc.xml", ms.ToArray());
// Document to Stream
ms = new MemoryStream();
XmlWriter xw = XmlWriter.Create(ms);
xDoc.WriteTo(xw);
xw.Flush();
ms.Position = 0;
transform = new XmlDsigC14NTransform();
transform.LoadInput(ms);
ms = (MemoryStream)transform.GetOutput(typeof(Stream));
File.WriteAllBytes(@"D:\Test\xml imza\ms.xml", ms.ToArray());
// node to stream
ms = new MemoryStream();
xw = XmlWriter.Create(ms);
nodeList[0].WriteTo(xw);
xw.Flush();
ms.Position = 0;
transform = new XmlDsigC14NTransform();
transform.LoadInput(ms);
ms = (MemoryStream)transform.GetOutput(typeof(Stream));
File.WriteAllBytes(@"D:\Test\xml imza\ms2.xml", ms.ToArray());
sign.xml
<?xml version="1.0" encoding="utf-8" ?>
<Root Attr="root" xmlns:test="http://www.test.com/xades#">
<Child1 Cttribute="c3" Attribute1="c1" Bttribute="c2">
<child11 Attribute11="c11">Element11</child11>
</Child1>
<Child2 Attribute2="c2">
<child21 Attribute21="c21">Element21</child21>
<child22 Attribute22="c22">Element22</child22>
</Child2>
<Child3 Attribute3="c3">
<child31 Attribute32="c31">
<child311 Attribute311="c311">Element311</child311>
</child31>
</Child3>
</Root>
Child1.xml
<Child1 xmlns:test="http://www.test.com/xades#"></Child1>
doc.xml
<Root xmlns:test="http://www.test.com/xades#" Attr="root">
<Child1 Attribute1="c1" Bttribute="c2" Cttribute="c3">
<child11 Attribute11="c11">Element11</child11>
</Child1>
<Child2 Attribute2="c2">
<child21 Attribute21="c21">Element21</child21>
<child22 Attribute22="c22">Element22</child22>
</Child2>
<Child3 Attribute3="c3">
<child31 Attribute32="c31">
<child311 Attribute311="c311">Element311</child311>
</child31>
</Child3> 
</Root>
ms.xml
<Root xmlns:test="http://www.test.com/xades#" Attr="root">
<Child1 Attribute1="c1" Bttribute="c2" Cttribute="c3">
<child11 Attribute11="c11">Element11</child11>
</Child1>
<Child2 Attribute2="c2">
<child21 Attribute21="c21">Element21</child21>
<child22 Attribute22="c22">Element22</child22>
</Child2>
<Child3 Attribute3="c3">
<child31 Attribute32="c31">
<child311 Attribute311="c311">Element311</child311>
</child31>
</Child3>
</Root>
ms2.xml
<Child1 Attribute1="c1" Bttribute="c2" Cttribute="c3">
<child11 Attribute11="c11">Element11</child11>
</Child1>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我想,你的答案就在你的问题中,“我真正想做的是规范化单个节点,但正如你在输出文件中看到的那样,输出不包含任何内部 xml。”
如果我理解您的意思,那么您确实不想想要规范化单个节点,或者您会很高兴它不包含内部 XML。您想要规范化单个子树。
XPath 返回节点,而不是子树。默认情况下,XPath 表达式返回的节点上的某些操作将包括其子节点和属性节点,但规范化故意不是其中之一,因为其中一些子节点可能会以您未签名的方式可变。在签名时,您仅对您所说的正在签名的节点进行签名。
将代码中的行从: 更改
为:
意味着我在 child1.xml 中得到以下内容:
我是否正确地认为这就是您想要的?
顺便说一句,沿着以下方向更精确:
可能有用,因为 xpath 评估可以在到达第一个
时停止,如果您的真实情况,性能增益可能会非常显着数据量大。
I think, your answer is in your question, "What I really want to do is to canonicalize a single node, but as you can see in the output file, the output does not contain any of the inner xml."
If I understand you, then really you don't want to canonicalise a single node, or you'd be happy that it doesn't contain the inner XML. You want to canonicalise a single subtree.
XPath returns nodes, not subtrees. Some operations on the nodes returned by an XPath expression will then include their child and attribute nodes by default, but canonicalisation deliberately isn't one of these, as potentially some of those very child nodes could be mutable in ways that you are not signing. In signing, you are only signing precisely those nodes that you say you are signing.
Changing the line in your code from:
to:
Means I get the following in child1.xml:
Am I correct in thinking that this is what you want?
Incidentally, more precision along the lines of:
May be useful, as then the xpath evaluation can stop when it gets to the first
</Child1>
, with a performance gain that could be significant if your real data is large.我可能在 MSDN 如果我正确地理解了问题。
这可以解决问题吗?:
在 child1.xml 中我有:
希望它有帮助。
托比亚斯
I found probably the solution at MSDN If I got the problem correctly.
Does this solve the problem?:
In child1.xml I have:
Hope it helped.
Tobias
您是否检查过 MSDN:http://msdn.microsoft.com/en-us /library/fzh48tx1.aspx 他们页面上的示例有一条注释,指出“此转换不包含内部 XML 元素”——这意味着一个已知问题。
您可以尝试不同的 XPath,例如 //child1/* 或 //child1|//child1/* 或 //child1// 或显式的 Nodes() 选择(在 http://msdn.microsoft.com/en-us/library/ms256471.aspx),但您处于灰色地带-用错误赌博。
因此,在您的 ms2.xml 中是您想要的实际输出,您暂时只需要进行中间序列化即可。
同时启动 Reflector 并看一下 - 这个类可能不是很复杂。
Have you checked MSDN: http://msdn.microsoft.com/en-us/library/fzh48tx1.aspx Sample on their page has a comment which says that "This transform does not contain inner XML elements" - meaning a known issue.
You could try different XPaths like //child1/* or //child1|//child1/* or //child1// or explicit nodes() selection (check full XPath syntax at http://msdn.microsoft.com/en-us/library/ms256471.aspx) but you are in a gray zone - gambling with a bug.
So, in your ms2.xml is the actual output you wanted you'll just have to do that intermediary serialization for the time being.
Also fire up Reflector and take a look - the class is probably not terribly complicated.
关于如何处理 XmlDocument 不区分源中的 U+000D(不应保留)与源中的显式引用(例如
)(应予以保留)。
而不是:
我们首先创建一个换行符清理 TextReader:
然后我们在加载 xDoc 中使用它:
然后在处理之前规范换行符,但保留显式内容。
A separate answer on how to deal with the fact that XmlDocument doesn't distinguish U+000D in the source (should not be preserved) from explicit references such as
in the source (should be preserved).
Instead of:
We first create a newline-cleaning TextReader:
We then use this in Loading the xDoc:
This then normalises newlines prior to processing, but leaves explicit alone.