首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有多变量名称空间的C#读取XML

具有多变量名称空间的C#读取XML
EN

Stack Overflow用户
提问于 2016-11-03 08:38:27
回答 2查看 2.6K关注 0票数 3

我必须从具有定义结构的XML中读取一些标记和属性,但是由于这些文件可以从不同的源生成,所以它们可以有不同的名称空间和前缀。

这是第一个XML示例。

代码语言:javascript
复制
<Order xmlns="urn:oasis:names:specification:ubl:schema:xsd:Order-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <cbc:UBLVersionID>2.1</cbc:UBLVersionID>
    <cbc:CustomizationID>urn:www.cenbii.eu:transaction:biitrns001:ver2.0:extended:urn:www.peppol.eu:bis:peppol3a:ver2.0:extended:urn:www.ubl-italia.org:spec:ordine:ver2.1</cbc:CustomizationID>
    <cbc:ID>ORD-001</cbc:ID>
    <cbc:IssueDate>2016-10-01</cbc:IssueDate>
    <cbc:OrderTypeCode listID="UNCL1001">221</cbc:OrderTypeCode>
    <cac:ValidityPeriod>
        <cbc:EndDate>2024-10-19</cbc:EndDate>
    </cac:ValidityPeriod>
    <cac:BuyerCustomerParty>
        <cac:Party>
            <cbc:EndpointID schemeID="IT:IPA">ITAK12MH</cbc:EndpointID>
            <cac:PartyIdentification>
                <cbc:ID schemeID="IT:VAT">01567570254</cbc:ID>
            </cac:PartyIdentification>
            <cac:PartyName>
                <cbc:Name>A Custom Name</cbc:Name>
            </cac:PartyName>
        </cac:Party>
    </cac:BuyerCustomerParty>
</Order>

这是第二个XML示例,具有不同的名称空间和前缀,但结构相同(标记、属性)。

代码语言:javascript
复制
<ns10:Order xmlns="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ns2="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:ns3="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:ns4="http://www.w3.org/2000/09/xmldsig#" xmlns:ns5="http://uri.etsi.org/01903/v1.3.2#" xmlns:ns6="urn:oasis:names:specification:ubl:schema:xsd:SignatureBasicComponents-2" xmlns:ns7="urn:oasis:names:specification:ubl:schema:xsd:SignatureAggregateComponents-2" xmlns:ns8="http://uri.etsi.org/01903/v1.4.1#" xmlns:ns9="urn:oasis:names:specification:ubl:schema:xsd:CommonSignatureComponents-2" xmlns:ns10="urn:oasis:names:specification:ubl:schema:xsd:Order-2">
    <UBLVersionID>2.1</UBLVersionID>
    <CustomizationID>urn:www.cenbii.eu:transaction:biitrns001:ver2.0:extended:urn:www.peppol.eu:bis:peppol3a:ver2.0:extended:urn:www.ubl-italia.org:spec:ordine:ver2.1</CustomizationID>
    <ID>ORD-001</ID>
    <IssueDate>2016-10-01</IssueDate>
    <OrderTypeCode listID="UNCL1001">221</OrderTypeCode>
    <ns3:ValidityPeriod>
        <EndDate>2024-10-19</EndDate>
    </ns3:ValidityPeriod>
    <ns3:BuyerCustomerParty>
        <ns3:Party>
            <EndpointID schemeID="IT:IPA">ITAK12MH</EndpointID>
            <ns3:PartyIdentification>
                <ID schemeID="IT:VAT">01567570254</ID>
            </ns3:PartyIdentification>
            <ns3:PartyName>
                <Name>A Custom Name</Name>
            </ns3:PartyName>
        </ns3:Party>
    </ns3:BuyerCustomerParty>
</ns10:Order>

这些文件必须被认为是相同的,因此两者都是有效的.

第三个示例可以是与第二个类似的文件,其中名称空间相同,但前缀不同。显然,重要的是用于匹配命名空间的前缀属于该特定标记。

我无法预先知道与名称空间相关联的前缀是什么.

代码语言:javascript
复制
<aaa:Order xmlns="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:aaa="urn:oasis:names:specification:ubl:schema:xsd:Order-2" xmlns:bbb="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2">
    <UBLVersionID>2.1</UBLVersionID>
    <CustomizationID>urn:www.cenbii.eu:transaction:biitrns001:ver2.0:extended:urn:www.peppol.eu:bis:peppol3a:ver2.0:extended:urn:www.ubl-italia.org:spec:ordine:ver2.1</CustomizationID>
    <ID>ORD-001</ID>
    <IssueDate>2016-10-01</IssueDate>
    <OrderTypeCode listID="UNCL1001">221</OrderTypeCode>
    <bbb:ValidityPeriod>
        <EndDate>2024-10-19</EndDate>
    </bbb:ValidityPeriod>
    <bbb:BuyerCustomerParty>
        <bbb:Party>
            <EndpointID schemeID="IT:IPA">ITAK12MH</EndpointID>
            <bbb:PartyIdentification>
                <ID schemeID="IT:VAT">01567570254</ID>
            </bbb:PartyIdentification>
            <bbb:PartyName>
                <Name>A Custom Name</Name>
            </bbb:PartyName>
        </bbb:Party>
    </bbb:BuyerCustomerParty>
</aaa:Order>

最后一个文件必须被视为与其他文件一样有效。

正如您所看到的,标记与它们的命名空间之间的关联总是相同的。唯一被改变的是前缀。

我的实际代码使用XDocument和XElement类来读取XML,但是它可以是这样的,因为我需要知道每个标记的确切前缀,而且由于它们可能不同,所以它只适用于第一个XML文件示例。

代码语言:javascript
复制
XDocument doc;
XmlNamespaceManager manager;

using (XmlReader reader = XmlReader.Create(stream))
{
    doc = XDocument.Load(reader);

    // Retrieving namespaces of XML file
    XPathNavigator navigator = doc.CreateNavigator();
    navigator.MoveToFollowing(XPathNodeType.Element);
    IDictionary<string, string> namespaces = navigator.GetNamespacesInScope(XmlNamespaceScope.All);

    // Add namespaces to an XmlNamespaceManager to read nodes
    manager = new XmlNamespaceManager(reader.NameTable);
    foreach (KeyValuePair<string, string> ns in namespaces)
    {
        manager.AddNamespace(ns.Key, ns.Value);
    }
}

XElement currentNode;

currentNode = doc.Root.XPathSelectElement("cbc:ID", manager);
if (currentNode != null)
    item.DespatchAdviceId = currentNode.Value;

currentNode = doc.Root.XPathSelectElement("cbc:IssueDate", manager);
if (currentNode != null)
{
    DateTime dataEmissione;
    if (DateTime.TryParseExact(currentNode.Value, validDateFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out dataEmissione))
        item.OrderIssueDate = dataEmissione;
}

currentNode = doc.Root.XPathSelectElement("cac:BuyerCustomerParty/cac:Party/cac:PartyIdentification/cbc:ID", manager);
if (currentNode != null)
{
    item.BuyerPartyId = currentNode.Value;
    if (currentNode.Attribute("schemeID") != null)
        item.BuyerPartySchemeId = currentNode.Attribute("schemeID").Value;
}

// ... and so on...

我如何读取XML而不必指定名称空间前缀?我应该使用另一个.NET库还是第三方库?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-11-03 08:47:29

使用LocalName,您可以在不添加名称空间的情况下对其进行linq。

代码语言:javascript
复制
//this is for <cbc:ID>ORD-001</cbc:ID>
var element = doc.Root.Elements().Where(x => x.Name.LocalName == "ID").FirstOrDefault();

如果您想进入嵌套元素

代码语言:javascript
复制
var element = doc.Root.Elements().Where(x => x.Name.LocalName == "ValidityPeriod").
                 Elements().Where(x=> x.Name.LocalName == "EndDate").FirstOrDefault();
票数 3
EN

Stack Overflow用户

发布于 2016-11-03 10:10:20

我需要知道每个标签的确切前缀。

不,没有。前缀与元素或属性的限定名完全无关。如果您想走XPath路线,那么不要从文档中读取名称空间和前缀来创建您的命名空间管理器,自己指定它们,这样您就知道它们是什么了。然后在查询中使用这些内容。例如,这将适用于任何XML文档:

代码语言:javascript
复制
var manager = new XmlNamespaceManager(new NameTable());

manager.AddNamespace("cbc", 
    "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2");

var id = doc.Root.XPathSelectElement("cbc:ID", manager);

不过,我要鼓励的是,你要抛弃XPath。LINQ到XML要好得多。另外一个快速提示是,有一个过载的接受流的XDocument.Load。没有必要创建XmlReader。所以:

代码语言:javascript
复制
XNamespace order = "urn:oasis:names:specification:ubl:schema:xsd:Order-2";
XNamespace cbc = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2";
XNamespace cac = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2";

var doc = XDocument.Load(stream);

var id = (string) doc.Elements(order + "Order")
    .Elements(cbc + "ID")
    .Single();

var issueDate = (DateTime) doc.Elements(order + "Order")
    .Elements(cbc + "IssueDate")
    .Single();

var buyerPartySchemeId = (string) doc.Descendants(cac + "BuyerCustomerParty")
    .Descendants(cbc + "ID")
    .Attributes("schemeID")
    .Single();
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40396966

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档