用XSLT替换XML属性中的换行符
我需要一些XSLT(或其他东西,请参见下文)来用替换字符替换所有属性中的换行符 我必须处理遗留XML,它将所有数据存储为属性,并使用新行表示基数。例如:用XSLT替换XML属性中的换行符,xml,xslt,xslt-2.0,Xml,Xslt,Xslt 2.0,我需要一些XSLT(或其他东西,请参见下文)来用替换字符替换所有属性中的换行符 我必须处理遗留XML,它将所有数据存储为属性,并使用新行表示基数。例如: <sample> <p att="John Paul Ringo"></p> </sample> 使用Saxon将以下内容应用于示例XML输出: John Paul Ringo 显然,这种格式不是我想要的-这只是为了试验replace()-但是在我们开始XSLT处理时,
<sample>
<p att="John
Paul
Ringo"></p>
</sample>
使用Saxon将以下内容应用于示例XML输出:
John Paul Ringo
显然,这种格式不是我想要的-这只是为了试验
replace()
-但是在我们开始XSLT处理时,换行符已经正常化了吗?如果是这样,是否有其他方法可以使用Java解析器将这些值解析为write?到目前为止,我只使用了JAXB。这似乎很难做到。正如我在中发现的那样,属性中的新行字符是有效的,但XML解析器将其规范化(),因此它可能在处理之前(因此在替换之前)丢失。XSLT仅在XML解析器处理完XML后才看到它,而XML解析器将完成属性值规范化
我认为一些XML解析器可以选择抑制属性值规范化。如果您不能访问这样的解析器,我认为用
解析之前的代码>可能是您的最佳逃生路线。以这种方式转义的换行不会因属性值规范化而飞溅。我通过使用预处理XML解决了这个问题(这是对@Ian Roberts关于使用非XML工具解析XML的评论的认可)。JSoup是(或曾经是)为HTML文档设计的,但是在这种上下文中工作得很好
我的代码如下:
@测试
public void verifyNewlineEscaping(){
最终列表节点=Parser.parseXmlFragment(FileUtils.readFileToString(sourcePath.toFile(),“UTF-8”),“”);
fixAttributeNewlines(节点);
//重构XML
StringBuilder输出=新的StringBuilder();
用于(节点:节点){
append(node.toString());
}
//将清除的输出打印到标准输出
系统输出打印项次(输出);
}
/**
*将XML属性中的换行符和周围的空格替换为
*为了避免将换行符转换为单个空格时出现空白规范化。
*
*
*如果将具有语义值的换行符错误地插入到
*属性值。
*
*
*@param nodes要更新的节点
*/
私有静态void fixAttributeNewlines(最终列表节点){
/*
*递归迭代XML文档中所有节点中的所有属性,执行
*属性字符串替换
*/
用于(最终节点:节点){
最终列表属性=node.attributes().asList();
for(最终属性:属性){
//JSoup将空白报告为属性
如果(!StringUtils.isWhitespace(attribute.getValue())){
attribute.setValue(attribute.getValue().replaceAll(\\s*\r?\n\\s*,“|”);
}
}
//递归处理子节点
如果(!node.childNodes().isEmpty()){
fixAttributeNewlines(node.childNodes());
}
}
}
对于我问题中的示例XML,此方法的输出为:
<sample>
<p att="John|Paul|Ringo"></p>
</sample>
请注意,我没有使用
因为JSoup在字符转义中相当谨慎,并且转义属性值中的所有内容。它还将现有的数字实体引用替换为其UTF-8等效项,因此时间会告诉我们这是否是一个可行的解决方案。我有一种非常不愉快的感觉,我可能需要戴上橡皮手套,在解析XML字符串之前在XML字符串上实现一个肮脏的正则表达式。不幸的是,我无法控制XML的产生。实际上,不,这太可怕了。如果属性值中的空格在语义上是重要的,那么你就不是在处理XML,而你需要使用非XML工具来处理它。解析器必须将属性值中的所有换行符转换为空格,如果您希望在解析后看到的值中包含换行符,则必须将其转义为字符引用(
;
),我不同意您的看法。XML是从一个应用程序导出的,该应用程序将保持匿名。这并不完全是应用程序的错,尽管将所有数据填充到属性中可能是一种有点可疑的方法。我怀疑用户通过使用新行解决了这个特定领域缺乏1:M基数的问题,应用程序盲目地将新行导出为XML。我可能会对任何为可疑XML设计的Java库进行一些研究-这不可能是一个孤立的实例,所以我肯定有人故意编写了一个松散/宽容的解析器。我也看到了这一点,但我希望他们仍然会在那里进行一些XSLT修复。此后,我通过不声称自己是XML解析器发现了解决问题的方法,这可能会使它不必遵守XML规范。现在我来试一试……只要大声想一想,您就可以这样做replace(/data/@value,'\s{2,10}','|')
-这不是绝对正确的,因为它依赖于将有多个空格而不是换行符,但它可以生成作业。@JirkaŠ。不,这是行不通的,因为XML解析器在数据到达XPath数据模型之前将属性值中所有连续的空格压缩到一个空格中。我担心这一点,但我在Altova中尝试过,它成功了。可能这只是Altova的特殊性。啊,我发现我错过了中的关键一句:“所有没有声明的属性都应该由非验证处理器处理,就像声明了CDATA一样。”-因此,如果没有DTD,解析器将用空格替换换行符,但不会将连续空格折叠为单个空格。谢谢Michael。在做了大量的挖掘之后,我想找出一个J
<sample>
<p att="John|Paul|Ringo"></p>
</sample>