使用Scala更改XML名称空间
我使用scala通过使用Scala更改XML名称空间,xml,scala,Xml,Scala,我使用scala通过scala.XML.XML.loadFile()方法从文件中加载XML文件。我正在处理的文档已经定义了名称空间,我希望使用scala将名称空间更改为其他名称空间。例如,文档的xmlns为“”,前缀为“a”-我想将文档的名称空间和前缀分别更改为“”和“b” 看起来很简单,我觉得我错过了一些明显的东西。从引用的loadFile()方法的返回Elem中获取名称空间没有问题。在这里。由于NamespaceBinding是嵌套的(每个ns都有一个父节点,TopScope除外),所以我们
scala.XML.XML.loadFile()
方法从文件中加载XML文件。我正在处理的文档已经定义了名称空间,我希望使用scala将名称空间更改为其他名称空间。例如,文档的xmlns为“”,前缀为“a”-我想将文档的名称空间和前缀分别更改为“”和“b”
看起来很简单,我觉得我错过了一些明显的东西。从引用的
loadFile()
方法的返回Elem
中获取名称空间没有问题。在这里。由于NamespaceBinding是嵌套的(每个ns都有一个父节点,TopScope除外),所以我们需要递归来解决这个问题。另外,每个ns都有一个URI和一个前缀,我们需要同时更改这两个
下面的函数将只更改一个特定的URI和前缀,它将检查所有名称空间,以查看前缀或URI是否需要更改。它将独立地更改前缀或URI,这可能不是所需要的。不过,解决这个问题没什么大不了的
至于其余部分,只需在Elem上进行模式匹配,即可递归到XML的每个部分。啊,是的,它也改变了元素的前缀。同样,如果这不是我们想要的,那么很容易改变
代码假定不需要递归到XML的“其他”部分——其余部分通常是文本元素。此外,它假定其他地方没有名称空间。我不是XML专家,所以我可能在这两方面都错了。再一次,改变这一点应该很容易——只需遵循模式即可
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]
}
def更换(el:Elem,
oldURI:String,newURI:String,
oldPrefix:String,newPrefix:String):元素={
def replace(what:String、before:String、after:String):String=
如果(what==before)后面还有什么
def fixScope(ns:NamespaceBinding):NamespaceBinding=
如果(ns==顶视)
顶镜
else新名称空间绑定(替换(ns.prefix、oldPrefix、newPrefix),
替换(ns.uri、oldURI、newURI),
fixScope(ns.parent))
def fixSeq(ns:Seq[Node]):Seq[Node]=for(Node)
元素(替换(前缀、旧前缀、新前缀),
标签,
attribs,
固定范围(范围),
fixSeq(儿童):*)
案例其他=>其他
}
修正顺序(el.theSeq)(0).作为[Elem]的替代
}
但是,这会产生一个意外的结果。作用域将添加到所有元素中。这是因为NamespaceBinding没有定义equals方法,因此使用了引用相等。我为它打开了一个票证,该票证已经关闭,因此Scala 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]
}
def更换(el:Elem,
oldURI:String,newURI:String,
oldPrefix:String,newPrefix:String):元素={
val namespaces=scala.collection.mutable.Map.empty[List[(String,String)],NamespaceBinding]
def replace(what:String、before:String、after:String):String=
如果(what==before)后面还有什么
def unfolns(ns:NamespaceBinding):列表[(字符串,字符串)]=ns匹配{
箱顶镜=>零
大小写\=>(ns.prefix,ns.uri)::展开ns(ns.parent)
}
def foldNS(unfoldns:List[(String,String)]):NamespaceBinding=unfoldns匹配{
如果namespaces.isDefinedAt(knownNS)=>名称空间(knownNS),则案例knownNS
大小写(前缀,uri)::tail=>
val newNS=新名称空间绑定(前缀、uri、foldNS(尾部))
名称空间(展开的名称)=新名称
纽恩斯
无案例=>顶镜
}
def fixScope(ns:NamespaceBinding):NamespaceBinding=
如果(ns==顶视)
ns
否则{
val Unfolderns=Unfolderns(ns)
val fixedNS=用于((前缀,uri)其他
}
修正顺序(el.theSeq)(0).作为[Elem]的替代
}
此处存在小错误。属性也可以有限定名称。您还需要检查这些名称