यहां यह है। चूंकि नेमस्पेस बाइंडिंग नेस्टेड किया गया है (प्रत्येक एनएस के पास टॉपस्कोप को छोड़कर माता-पिता हैं), हमें इसे ठीक करने के लिए पुन: प्रयास करने की आवश्यकता है। इसके अलावा, प्रत्येक एनएस में एक यूआरआई और एक उपसर्ग है, और हमें दोनों को बदलने की जरूरत है।
नीचे दिया गया कार्य केवल एक विशेष यूआरआई और उपसर्ग को बदल देगा, और यह सभी नामस्थानों की जांच करेगा, यह देखने के लिए कि क्या उपसर्ग या यूआरआई को बदलने की जरूरत है या नहीं। यह एक उपसर्ग या एक दूसरे से स्वतंत्र यूआरआई को बदल देगा, जो शायद वांछित नहीं हो सकता है। हालांकि, यह एक बड़ा सौदा तय नहीं है।
बाकी के लिए, एक्सएमएल के प्रत्येक भाग में रिकर्स करने के लिए सिर्फ एलेम पर पैटर्न मिलान होता है। आह, हाँ, यह तत्वों के उपसर्ग भी बदलता है। दोबारा, अगर वह नहीं चाहता है, तो इसे बदलना आसान है।
कोड मानता है कि एक्सएमएल के "अन्य" हिस्सों में पुन: प्रयास करने की कोई आवश्यकता नहीं है - शेष आमतौर पर पाठ तत्व होंगे। साथ ही, यह मानता है कि कहीं और नामस्थान नहीं है। मैं एक्सएमएल पर कोई विशेषज्ञ नहीं हूं, इसलिए मैं दोनों गिनती पर गलत हो सकता हूं। एक बार और, इसे बदलना आसान होना चाहिए - बस पैटर्न का पालन करें।
def changeNS(el: Elem,
oldURI: String, newURI: String,
oldPrefix: String, newPrefix: String): Elem = {
def replace(what: String, before: String, after: String): String =
if (what == before) after else what
def fixScope(ns: NamespaceBinding): NamespaceBinding =
if(ns == TopScope)
TopScope
else new NamespaceBinding(replace(ns.prefix, oldPrefix, newPrefix),
replace(ns.uri, oldURI, newURI),
fixScope(ns.parent))
def fixSeq(ns: Seq[Node]): Seq[Node] = for(node <- ns) yield node match {
case Elem(prefix, label, attribs, scope, children @ _*) =>
Elem(replace(prefix, oldPrefix, newPrefix),
label,
attribs,
fixScope(scope),
fixSeq(children) : _*)
case other => other
}
fixSeq(el.theSeq)(0).asInstanceOf[Elem]
}
हालांकि यह एक अप्रत्याशित परिणाम उत्पन्न करता है। दायरे सभी तत्वों में जोड़ा जा रहा है। ऐसा इसलिए है क्योंकि नेमस्पेस बाइंडिंग एक समान विधि को परिभाषित नहीं करता है, इस प्रकार संदर्भ समानता का उपयोग करता है। मैंने इसके लिए टिकट खोला है, 2138, जो पहले ही बंद कर दिया गया है, इसलिए स्कैला 2.8 में यह समस्या नहीं होगी।
इस बीच, निम्न कोड ठीक से काम करेगा। यह नामस्थानों का कैश रखता है। यह नामकरण से पहले एक सूची में नेमस्पेस बाइंडिंग को भी विघटित करता है।
def changeNS(el: Elem,
oldURI: String, newURI: String,
oldPrefix: String, newPrefix: String): Elem = {
val namespaces = scala.collection.mutable.Map.empty[List[(String, String)],NamespaceBinding]
def replace(what: String, before: String, after: String): String =
if (what == before) after else what
def unfoldNS(ns: NamespaceBinding): List[(String, String)] = ns match {
case TopScope => Nil
case _ => (ns.prefix, ns.uri) :: unfoldNS(ns.parent)
}
def foldNS(unfoldedNS: List[(String, String)]): NamespaceBinding = unfoldedNS match {
case knownNS if namespaces.isDefinedAt(knownNS) => namespaces(knownNS)
case (prefix, uri) :: tail =>
val newNS = new NamespaceBinding(prefix, uri, foldNS(tail))
namespaces(unfoldedNS) = newNS
newNS
case Nil => TopScope
}
def fixScope(ns: NamespaceBinding): NamespaceBinding =
if(ns == TopScope)
ns
else {
val unfoldedNS = unfoldNS(ns)
val fixedNS = for((prefix, uri) <- unfoldedNS)
yield (replace(prefix, oldPrefix, newPrefix), replace(uri, oldURI, newURI))
if(!namespaces.isDefinedAt(unfoldedNS))
namespaces(unfoldedNS) = ns // Save for future use
if(fixedNS == unfoldedNS)
ns
else
foldNS(fixedNS)
}
def fixSeq(ns: Seq[Node]): Seq[Node] = for(node <- ns) yield node match {
case Elem(prefix, label, attribs, scope, children @ _*) =>
Elem(replace(prefix, oldPrefix, newPrefix),
label,
attribs,
fixScope(scope),
fixSeq(children) : _*)
case other => other
}
fixSeq(el.theSeq)(0).asInstanceOf[Elem]
}