我正在创建一个XML替换实用程序,它将替换XML文件中的属性。但由于某种原因,如果我试图替换的属性包含一个&符号,我写的布尔方法(isreplacementEntry)没有正确处理它。我的代码如下
/**
* This method is used to iterate over the entirety of the xml presented and modify the XML attribute desired while
* keeping old XML values
* @param elem the XML you pass in (generally from file, input stream or string)
* @param attrName name of the attribute you want to replace
* @param curVal value of the current attribute
* @return
*/
def replaceXMLEntryAttribute(elem: Elem, attrName: String, curVal: String, desiredVal: String): Node = {
def replace: Node => Node =
{
case e: Elem if isReplacementEntry(e, attrName, curVal) ⇒ generateReplacementXMLAttribute(e)
case e: Elem ⇒ e.copy(
child = e.child.map { replace(_) }
)
case other⇒ other
}
def generateReplacementXMLAttribute(node: Elem): Elem = {
println("gets here")
val currentXML= node.toString()
val newAttr= currentXML.replaceAllLiterally("\""+curVal, "\""+desiredVal)
XML.loadString(newAttr)
}
replace(elem)
}
/**
* This method checks whether
* @param node The elements from which you wish to check if such an attribute exists
* @param attributeName The name of the attribute to modify
* @param currentAttrValue The current value of thr attribute that will eventually be modified
* @return
*/
private def isReplacementEntry(node: Elem, attributeName: String, currentAttrValue: String): Boolean = {
/* val test = node.mkString)
println(test)*/
val attr = "@" + attributeName
val exists = node \\ attr find { _.text == currentAttrValue }
exists match{
case None => false
case _ => true
}
}
具体来说,此行val exists = node \\ attr find { _.text == currentAttrValue }
始终返回false。我试过的东西是使用scala.xml.Utility.escape和当前的Attr Value,但它似乎仍然不起作用。
这个应该使用的示例XML是
<?xml version="1.0"?>
<Stuff expression="test">
<Rule expression="threshold <= 20 AND '${userID}' IN ('USER1','USER2','USER_7','USER_09')"/>
</Stuff>
我试图用规则
替换该行答案 0 :(得分:1)
第一个问题可能是您正在寻找错误的字符串。 XML中的&符号表示字符引用的开头,当您调用elem.text
时,它们将替换为相应的字符。尝试在Scala控制台中运行以下行:<foo attr="<"/> \@ "attr"
。它会生成字符串<
。
因此,对于给定的XML,参数应如下所示:
replaceXMLEntryAttribute(
yourXml,
"expression",
"threshold <= 20 AND '${userID}' IN ('USER1','USER2','USER_7','USER_09')",
"some new value")
这仍然不够,因为你在XML的序列化字符串表示中字面替换了值, 那些放大器。因此,即使您在isReplacementEntry
中找到了某些属性,也无法在generateReplacementXMLAttribute
中替换它。相反,在元素上使用属性替换运算符%
可能更容易,更安全:
def generateReplacementXMLAttribute(node: Elem): Elem =
node % xml.Attribute(attrName, xml.Text(desiredVal), xml.Null)
但问题是,这只会替换其参数的直接属性,但在isReplacementEntry
中您与\\
匹配,因此如果任意,它将返回true
descendant元素具有所需值的属性。相反,只有当元素具有自己的具有此值的属性时,它才应为true
:
private def isReplacementEntry(node: Elem, attributeName: String, currentAttrValue: String): Boolean =
node \@ attributeName == currentAttrValue
所以这里是代码的完整工作版本(没有Scaladoc)。请注意,您要搜索的值应该使用实际字符替换字符引用:
def replaceXMLEntryAttribute(elem: Elem, attrName: String, curVal: String, desiredVal: String): Node = {
def replace: Node => Node = {
case e: Elem if isReplacementEntry(e, attrName, curVal) ⇒
generateReplacementXMLAttribute(e)
case e: Elem ⇒ e.copy(child = e.child map replace)
case other ⇒ other
}
def generateReplacementXMLAttribute(node: Elem): Elem =
node % xml.Attribute(attrName, xml.Text(desiredVal), xml.Null)
replace(elem)
}
private def isReplacementEntry(node: Elem, attributeName: String, currentAttrValue: String): Boolean =
node \@ attributeName == currentAttrValue
println(replaceXMLEntryAttribute(
<Stuff expression="test">
<Rule expression="threshold <= 20 AND '${userID}' IN ('USER1','USER2','USER_7','USER_09')"/>
</Stuff>,
"expression",
"threshold <= 20 AND '${userID}' IN ('USER1','USER2','USER_7','USER_09')",
"foobar"))