簡體   English   中英

如何更改某些元素的XML命名空間

[英]How To change XML namespace of certain element

我有一些xml通過一些WCF消息的xmlserialization生成。 現在我想制作一個通用的方法,我將提供一個xml文件名和一個像mailxml12這樣的前綴。 然后在xml文件中,名稱中沒有任何名稱空間前綴的元素應替換為mailxml12:

像源文件是:

<DeliveryApptCreateRequest d2p1:ApptType="Pallet" d2p1:PickupOrDelivery="Delivery" d2p1:ShipperApptRequestID="4490660303D5" d2p1:SchedulerCRID="234234" xmlns:d2p1="http://idealliance.org/Specs/mailxml12.0a/mailxml_defs" xmlns="http://idealliance.org/Specs/mailxml12.0a/mailxml_tm">
<SubmittingParty d2p1:MailerID6="123446" d2p1:CRID="342343" d2p1:MaildatUserLicense="A123" />
<SubmittingSoftware d2p1:SoftwareName="asds" d2p1:Vendor="123" d2p1:Version="12" />
<SubmitterTrackingID>2CAD3F71B4405EB16392</SubmitterTrackingID>
<DestinationEntry>No</DestinationEntry>
<OneTimeAppt>
  <PreferredAppt>2012-06-29T09:00:00Z</PreferredAppt>
</OneTimeAppt>    
<TrailerInfo>
  <Trailer>
    <TrailerNumber>A</TrailerNumber>
    <TrailerLength>20ft</TrailerLength>
  </Trailer>
  <Carrier>
    <CarrierName>N/A</CarrierName>
    <URL>http://test.com</URL>
  </Carrier>
  <BillOfLadingNumber>N/A</BillOfLadingNumber>
</TrailerInfo>   
</DeliveryApptCreateRequest>

在所需的方法之后,應將其更改為所有沒有mailxml:前綴的元素名稱mailxml: DeliveryApptCreateRequest應該成為mailxml:DeliveryApptCreateRequest而像d2p1:CompanyName這樣的元素應保持原樣。

我試過以下代碼

 private void RepalceFile(string xmlfile)
    {
        XmlDocument doc = new XmlDocument();
        doc.Load(xmlfile);
        var a = doc.CreateAttribute("xmlns:mailxml12tm");
        a.Value = "http://idealliance.org/Specs/mailxml12.0a/mailxml_tm";
        doc.DocumentElement.Attributes.Append(a);
        doc.DocumentElement.Prefix = "mailxml12tm";

        foreach (XmlNode item in doc.SelectNodes("//*"))
        {
            if (item.Prefix.Length == 0)
                item.Prefix = "mailxml12tm";
        }
        doc.Save(xmlfile);
    }

唯一的問題是根元素保持原樣,而所有根據我的需要進行更改

您可以將整個XML解析為字符串,並在適當的位置插入名稱空間。 但是,此解決方案可以創建許多僅在算法中使用的新字符串,這對性能不利。 但是,我已經編寫了一個以這種方式解析它的函數,它似乎對你發布的樣本XML運行得非常快;)。 如果你想使用它,我可以發布它。

另一個解決方案是將XML作為XmlDocument加載,並利用它是樹狀結構的事實。 這樣,您可以在適當的位置以遞歸方式添加適當的名稱空間。 不幸的是, XmlNode.Name屬性是只讀的,這就是為什么你必須手動復制xml的整個結構來更改某些節點的名稱的原因。 我現在沒有時間編寫代碼,所以我只是讓你寫它。 如果您遇到任何問題,請告訴我。

更新

我已經測試了Jeff Mercado建議的代碼和代碼,並且它們似乎都正常工作,至少在您在問題中發布的示例XML中。 確保您嘗試解析的XML與您發布的XML相同。

只是為了使它工作並解決最初提出的添加命名空間問題,您可以使用代碼,它將整個XML作為String並手動解析:

private static String UpdateNodesWithDefaultNamespace(String xml, String defaultNamespace)
    {
        if (!String.IsNullOrEmpty(xml) && !String.IsNullOrEmpty(defaultNamespace))
        {
            int currentIndex = 0;

            while (currentIndex != -1)
            {
                //find index of tag opening character
                int tagOpenIndex = xml.IndexOf('<', currentIndex);

                //no more tag openings are found
                if (tagOpenIndex == -1)
                {
                    break;
                }

                //if it's a closing tag
                if (xml[tagOpenIndex + 1] == '/')
                {
                    currentIndex = tagOpenIndex + 1;
                }
                else
                {
                    currentIndex = tagOpenIndex;
                }

                //find corresponding tag closing character
                int tagCloseIndex = xml.IndexOf('>', tagOpenIndex);
                if (tagCloseIndex <= tagOpenIndex)
                {
                    throw new Exception("Invalid XML file.");
                }

                //look for a colon within currently processed tag
                String currentTagSubstring = xml.Substring(tagOpenIndex, tagCloseIndex - tagOpenIndex);
                int firstSpaceIndex = currentTagSubstring.IndexOf(' ');
                int nameSpaceColonIndex;
                //if space was found
                if (firstSpaceIndex != -1)
                {
                    //look for namespace colon between tag open character and the first space character
                    nameSpaceColonIndex = currentTagSubstring.IndexOf(':', 0, firstSpaceIndex);
                }
                else
                {
                    //look for namespace colon between tag open character and tag close character
                    nameSpaceColonIndex = currentTagSubstring.IndexOf(':');
                }

                //if there is no namespace
                if (nameSpaceColonIndex == -1)
                {
                    //insert namespace after tag opening characters '<' or '</'
                    xml = xml.Insert(currentIndex + 1, String.Format("{0}:", defaultNamespace));
                }

                //look for next tags after current tag closing character
                currentIndex = tagCloseIndex;
            }
        }

        return xml;
    }

您可以檢查此代碼以使應用程序正常工作,但是,我強烈建議您確定其他解決方案建議無效的原因。

由於在這種情況下您定義了默認命名空間,因此您可以刪除默認命名空間聲明,並使用舊命名空間名稱為新前綴添加新聲明,從而有效地替換它。

var prefix = "mailxml";
var content = XElement.Parse(xmlStr);
var defns = content.GetDefaultNamespace();
content.Attribute("xmlns").Remove();
content.Add(new XAttribute(XNamespace.Xmlns + prefix, defns.NamespaceName));

@ JeffMercado的解決方案對我不起作用(可能因為我沒有默認命名空間)。

我最終使用:

XNamespace ns = Constants.Namespace;
el.Name = (ns + el.Name.LocalName) as XName;

要更改我使用的整個文檔的命名空間:

private void rewriteNamespace(XElement el)
{
    // Change namespace
    XNamespace ns = Constants.Namespace;
    el.Name = (ns + el.Name.LocalName) as XName;

    if (!el.HasElements)
        return;

    foreach (XElement d in el.Elements())
        rewriteNamespace(d);
}

用法:

var doc = XDocument.parse(xmlStr);
rewriteNamespace(doc.Root)

HTH

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM