【问题标题】:c# XPathSelectElement return null even if the namespace is specifiedc# XPathSelectElement即使指定了命名空间也返回null
【发布时间】:2022-01-17 17:24:13
【问题描述】:

我在一个文件中有这个 xml 文档:

<samlp:AuthnRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_73c4b43a-d201-4990-b656-e6bab19e1c09" Version="2.0" IssueInstant="2021-12-14T08:09:39.816485Z" Destination="https://localhost/idp/sso/post" ForceAuthn="true" AssertionConsumerServiceIndex="0" AssertionConsumerServiceURL="https://localhost:5002/signin-spid" AttributeConsumingServiceIndex="0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" >
<saml:Issuer NameQualifier="https://localhost:5002" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" >https://localhost:5002</saml:Issuer>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
        <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
        <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
        <Reference URI="#_73c4b43a-d201-4990-b656-e6bab19e1c09">
            <Transforms>
                <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
            <DigestValue>.........DigestValue...........</DigestValue>
        </Reference>
    </SignedInfo>
    <SignatureValue>..............Signature................</SignatureValue>
    <KeyInfo>
        <X509Data>
            <X509Certificate>...........Certificate.............</X509Certificate>
        </X509Data>
    </KeyInfo>
</Signature>
<samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" />
<saml:Conditions NotBefore="2021-12-14T07:59:39.816485Z" NotOnOrAfter="2021-12-14T08:19:39.816485Z" />
</samlp:AuthnRequest>

我只是想用这段代码获取 SignatureValue 标记值和 X509Certificate 标记值:

var xDocument = XDocument.Load("Request.xml");
var reader = xDocument.CreateReader();

var namespaceManager = new XmlNamespaceManager(reader.NameTable);
namespaceManager.AddNamespace("", "http://www.w3.org/2000/09/xmldsig#");
var signature = xDocument.XPathSelectElement("/Signature/SignatureValue", namespaceManager);
var x509Certificate = xDocument.XPathSelectElement("/Signature/KeyInfo/X509Data/X509Certificate", namespaceManager);

但 Signature 和 x509Certificate 元素始终为空。 我也尝试直接在 Root 对象上使用该方法,但效果不一样。我做错了什么?
谢谢

【问题讨论】:

  • 在这里使用XmlReaderXPathSelectElement吗?有使用 LINQ to XML 获取正确元素的更简单方法。请注意,您要的是 /Signature,但根元素是 AuthnRequest,然后是其中的 Signature。也许这就是问题所在?
  • 我只是使用了 / 为什么它应该在 AuthnRequest 下下降一个节点,但无论如何即使指定 AuthnRequest / Signature 也不起作用
  • 好的,关于您是否使用 XPathSelectElement 的问题呢?如果您对使用 Element 方法感到满意,那么这很简单。
  • 我现在正在使用其他方法,但我真的很好奇为什么它不起作用
  • 好的,如果您的问题是特定于使用 NamespaceManager,请修复示例以包含 /AuthnRequest。但我怀疑docs.microsoft.com/en-us/dotnet/api/… 中的注释在这里是相关的——我怀疑你应该指定一个非空前缀。

标签: c# xml xpath .net-5


【解决方案1】:

最好使用 LINQ to XML API。

自 2007 年起在 .Net Framework 中可用。

c#

void Main()
{
    const string filename = @"e:\Temp\pampua84.xml";

    XDocument xdoc = XDocument.Load(filename);
    XNamespace ns = "http://www.w3.org/2000/09/xmldsig#";
    

    string SignatureValue = xdoc.Descendants(ns + "SignatureValue")
        .FirstOrDefault()?.Value;

    string X509Certificate = xdoc.Descendants(ns + "X509Certificate")
        .FirstOrDefault()?.Value;

    Console.WriteLine("SignatureValue='{0}'", SignatureValue);
    Console.WriteLine("X509Certificate='{0}'", X509Certificate);
}

【讨论】:

    【解决方案2】:

    这是一个快速的。您必须为空的默认命名空间提供前缀。它可以是任何东西,在这个例子中我称之为“root”。

    using System.Xml;
    
    NameTable nt = new NameTable();
    XmlNamespaceManager nsmgr = new XmlNamespaceManager(nt);
    nsmgr.AddNamespace("root", "http://www.w3.org/2000/09/xmldsig#");
    
    XmlDocument xml = new XmlDocument();
    xml.Load("c:\\temp\\test.xml");
    XmlNode ndSignature = xml.SelectSingleNode("//root:Signature/root:SignatureValue", nsmgr);
    XmlNode ndCertificate = xml.SelectSingleNode("//root:Signature/root:KeyInfo/root:X509Data/root:X509Certificate", nsmgr);
    
    Console.WriteLine(ndSignature.InnerText);
    Console.WriteLine(ndCertificate.InnerText);
    

    【讨论】:

    • 谢谢,问题只是指出前缀并将其放在每个孩子的名字之前。它与以下代码完美配合:``` xmlNamespaceManager.AddNamespace("sig", "w3.org/2000/09/xmldsig#"); var signatureValue = xDocument.XPathSelectElement("//sig:Signature/sig:SignatureValue", xmlNamespaceManager); ```
    • 名称空间产生的问题比解决的问题多。不知何故,我们都可以使用分层文件系统,而不必担心 2 个同名文件。我们只知道将它们放在不同的文件夹中(=父元素)。我一直不明白为什么 XML 元素有什么不同。
    猜你喜欢
    • 2016-06-11
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多