5

System.Security.Cryptography.Xml.XMLDsigC14nTransformc# .net Framework 2.0 のクラスを使用して、xml ノードを正規化しようとしています。

このインスタンスは、NodeList、Stream、および XMLDocument の 3 つの異なる入力タイプを想定しています。これらすべての入力タイプで変換を試みましたが、異なる結果が得られました。私が本当にやりたいことは、単一のノードを正規化することですが、出力ファイルでわかるように、出力には内部の 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">&#xD;
  <Child1 Attribute1="c1" Bttribute="c2" Cttribute="c3">&#xD;
    <child11 Attribute11="c11">Element11</child11>&#xD;
  </Child1>&#xD;
  <Child2 Attribute2="c2">&#xD;
    <child21 Attribute21="c21">Element21</child21>&#xD;
    <child22 Attribute22="c22">Element22</child22>&#xD;
  </Child2>&#xD;
  <Child3 Attribute3="c3">&#xD;
    <child31 Attribute32="c31">&#xD;
      <child311 Attribute311="c311">Element311</child311>&#xD;
    </child31>&#xD;
  </Child3>  &#xD;
</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>
4

4 に答える 4

4

あなたの答えはあなたの質問にあると思います。

私があなたを理解していれば、本当に単一のノードを正規化したくないか、内部の XML が含まれていないことを喜んでいるでしょう。単一のサブツリーを正規化したい。

XPath はサブツリーではなくノードを返します。XPath 式によって返されるノードに対する一部の操作には、デフォルトでその子ノードと属性ノードが含まれますが、正規化は意図的にこれらの 1 つではありません。署名では、署名していると言うノードのみに正確に署名します。

コードの行を次のように変更します。

XmlNodeList nodeList = xDoc.SelectNodes("//Child1");

に:

XmlNodeList nodeList =
    xDoc.SelectNodes("//Child1/descendant-or-self::node()|//Child1//@*");

child1.xml で次を取得することを意味します。

<Child1 xmlns:test="http://www.test.com/xades#" Attribute1="c1" Bttribute="c2" Cttribute="c3">&#xD;
    <child11 Attribute11="c11">Element11</child11>&#xD;
  </Child1>

これがあなたが望むものだと考えるのは正しいですか?

ちなみに、次の行に沿って精度が向上します。

XmlNodeList nodeList =
    xDoc.SelectNodes("//Child1[1]/descendant-or-self::node()|//Child1[1]//@*");

</Child1>実際のデータが大きい場合、パフォーマンスが大幅に向上する可能性があり、最初の に到達したときに xpath 評価を停止できるため、便利な場合があります。

于 2010-08-06T19:22:52.393 に答える
1

問題が正しく発生した場合、 MSDNでおそらく解決策を見つけました。

これで問題は解決しましたか?:

string path = @"sign.xml";
var xDoc = new XmlDocument();
xDoc.PreserveWhitespace = true;
using (var fs = new FileStream(path, FileMode.Open))
{
    xDoc.Load(fs);
}

// canon node list
XmlNodeList nodeList = xDoc.SelectNodes("//Child1");

var transform = new XmlDsigC14NTransform(true)
                    {
                        Algorithm = SignedXml.XmlDsigExcC14NTransformUrl
                    };

var validInTypes = transform.InputTypes;
var inputType = nodeList.GetType();
if (!validInTypes.Any(t => t.IsAssignableFrom(inputType)))
{
    throw new ArgumentException("Invalid Input");
}

transform.LoadInput(xDoc);
var innerTransform = new XmlDsigC14NTransform();

innerTransform.LoadInnerXml(xDoc.SelectNodes("//."));
var ms = (MemoryStream) transform.GetOutput(typeof (Stream));
ms.Flush();
File.WriteAllBytes(@"child1.xml", ms.ToArray());

child1.xml には次のものがあります。

<Root xmlns:test="http://www.test.com/xades#" Attr="root">&#xD;
  <Child1 Attribute1="c1" Bttribute="c2" Cttribute="c3">&#xD;
    <child11 Attribute11="c11">Element11</child11>&#xD;
  </Child1>&#xD;
  <Child2 Attribute2="c2">&#xD;
    <child21 Attribute21="c21">Element21</child21>&#xD;
    <child22 Attribute22="c22">Element22</child22>&#xD;
  </Child2>&#xD;
  <Child3 Attribute3="c3">&#xD;
    <child31 Attribute32="c31">&#xD;
      <child311 Attribute311="c311">Element311</child311>&#xD;
    </child31>&#xD;
  </Child3>&#xD;
</Root>

それが役に立ったことを願っています。トバイアス

于 2010-08-02T18:42:44.507 に答える
0

XmlDocumentがソース内のU+000D(保存されるべきではない)と&#xd;ソース内などの明示的な参照(保存されるべき)を区別しないという事実に対処する方法に関する別の回答。

それ以外の:

using (FileStream fs = new FileStream(path, FileMode.Open))
{
    xDoc.Load(fs);
}

まず、改行を消去するTextReaderを作成します。

private class LineCleaningTextReader : TextReader
{
  private readonly TextReader _src;
  public LineCleaningTextReader(TextReader src)
  {
    _src = src;
  }
  public override int Read()
  {
    int r = _src.Read();
    switch(r)
    {
      case 0xD:// \r
        switch(_src.Peek())
        {
          case 0xA: case 0x85: // \n or NEL char
            _src.Read();
            break;
        }
        return 0xA;
      case 0x85://NEL
        return 0xA;
      default:
        return r;
    }
  }
}

次に、これをxDocのロードで使用します。

using (FileStream fs = new FileStream(path, FileMode.Open))
{
  using(TextReader tr = new StreamReader(fs))
    xDoc.Load(new LineCleaningTextReader(tr));
}

これにより、処理前に改行が正規化されますが、明示的なままになります。

于 2010-08-10T14:46:20.907 に答える
0

MSDN を確認しましたか: http://msdn.microsoft.com/en-us/library/fzh48tx1.aspxページのサンプルには、「この変換には内部 XML 要素が含まれていません」というコメントがあります。これは、既知の問題を意味します。

//child1/* または //child1|//child1/* または //child1// または明示的な nodes() 選択などのさまざまな XPath を試すことができます ( http://msdn.microsoft.com/enで完全な XPath 構文を確認してください)。 -us/library/ms256471.aspx ) しかし、あなたはグレーゾーンにいます - バグでギャンブルしています.

したがって、ms2.xml には、必要な実際の出力があり、当面はその中間シリアル化を行う必要があります。

また、Reflector を起動して見てみましょう。クラスはおそらくそれほど複雑ではありません。

于 2010-08-03T11:41:09.027 に答える