7

いくつかの WCF メッセージの xmlserialization を介して生成された xml のセットがあります。ここで、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:。like 要素 likeはそのままにしておく必要がありますDeliveryApptCreateRequestmailxml:DeliveryApptCreateRequestd2p1: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);
    }

唯一の問題は、必要に応じてすべてが変更されている間、ルート要素がそのまま残ることです

4

3 に答える 3

2

XML 全体を文字列として解析し、適切な場所に名前空間を挿入するだけです。ただし、このソリューションでは、アルゴリズム内でのみ使用される多くの新しい文字列が作成される可能性があり、パフォーマンスには適していません。ただし、この方法で解析する関数を作成しましたが、投稿したサンプル XML では非常に高速に実行されるようです ;)。使いたいと思ったら載せます。

もう 1 つの解決策は、XML をXmlDocumentとして読み込み、それがツリー状の構造であることを利用することです。このようにして、必要に応じて適切な名前空間を再帰的に追加するメソッドを作成できます。残念ながら、XmlNode.Name属性は読み取り専用であるため、一部のノードの名前を変更するには、xml の構造全体を手動でコピーする必要があります。今はコードを書く時間がないので、あなたに書かせてください。問題が発生した場合は、お知らせください。

アップデート

あなたのコードとJeff Mercadoが提案したコードをテストしましたが、少なくとも質問に投稿したサンプル 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;
    }

アプリを動作させるためにこのコードを確認できますが、提案された他の解決策が機能しなかった理由を特定することを強くお勧めします。

于 2012-06-19T19:18:01.673 に答える
1

@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

于 2016-05-03T08:59:15.193 に答える
1

この場合、デフォルトの名前空間が定義されているため、デフォルトの名前空間宣言を削除し、古い名前空間名を使用して新しいプレフィックスの新しい宣言を追加し、効果的に置き換えることができます。

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));
于 2012-06-19T22:52:43.400 に答える