给出以下xml文件,知道结构和内容可以更改:
<something>
<parent>
<child>Bird is the word 1.</child>
<child>Curd is the word 2.</child>
<child>Nerd is the word 3.</child>
</parent>
<parent>
<child>Bird is the word 4.</child>
<child>Word is the word 5.</child>
<child>Bird is the word 6.</child>
</parent>
</something>
我想用一种方法来使用xquery(甚至xslt)将所提供的字符串的所有实例替换为另一个。例如,将“Bird”替换为“Dog”。因此结果将是:
<something>
<parent>
<child>Dog is the word 1.</child>
<child>Curd is the word 2.</child>
<child>Nerd is the word 3.</child>
</parent>
<parent>
<child>Dog is the word 4.</child>
<child>Word is the word 5.</child>
<child>Dog is the word 6.</child>
</parent>
</something>
我不知道这是否可能。我所做的每一次尝试都消除了标签。我甚至尝试过这个例子(http://geekswithblogs.net/Erik/archive/2008/04/01/120915.aspx),但是文本不是整个文档。
请帮忙!
更新
我尝试使用xslt 2.0建议,因为它似乎最合适。在尝试根据我的情况对其进行修改时,我一直在干涸。
我想传入一个xml参数来定义替换。所以,像这样修改xslt:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="list">
<words>
<word>
<search>Bird</search>
<replace>Dog</replace>
</word>
<word>
<search>word</search>
<replace>man</replace>
</word>
</words>
</xsl:param>
<xsl:template match="@*|*|comment()|processing-instruction()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:param name="chosen" select="." />
<xsl:for-each select="$list//word">
<xsl:variable name="search"><xsl:value-of select="search" /></xsl:variable>
<xsl:analyze-string select="$chosen" regex="{$search}">
<xsl:matching-substring><xsl:value-of select="replace" /></xsl:matching-substring>
<xsl:non-matching-substring><xsl:value-of select="$chosen"/></xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
结果是:
<something>
<parent>
<child>Bird is the word 1.Bird is the word 1.</child>
<child>Curd is the word 2.Curd is the word 2.</child>
<child>Nerd is the word 3.Nerd is the word 3.</child>
</parent>
<parent>
<child>Bird is the word 4.Bird is the word 4.</child>
<child>Word is the word 5.Word is the word 5.</child>
<child>Bird is the word 6.Bird is the word 6.</child>
</parent>
</something>
毋庸置疑,但是,我不希望它重复,也不正确。
请帮助!
答案 0 :(得分:7)
如果XQuery和XSLT都是一个选项,那么你可能使用XSLT 2.0处理器。如果是这样,这应该有效:
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="search" select="'Bird'"/>
<xsl:param name="replace" select="'Dog'"/>
<xsl:template match="@*|*|comment()|processing-instruction()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:analyze-string select="." regex="{$search}">
<xsl:matching-substring><xsl:value-of select="$replace"/></xsl:matching-substring>
<xsl:non-matching-substring><xsl:value-of select="."/></xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
使用问题中的XML输入,此XSLT生成以下输出:
<something>
<parent>
<child>Dog is the word 1.</child>
<child>Curd is the word 2.</child>
<child>Nerd is the word 3.</child>
</parent>
<parent>
<child>Dog is the word 4.</child>
<child>Word is the word 5.</child>
<child>Dog is the word 6.</child>
</parent>
</something>
注意:在创建输出时,不会更改元素/属性/注释/处理指令。
修改强>
您获得重复项的原因是因为您的xsl:for-each
正在循环使用两个word
元素。如果你有3,它将输出文本3次。
你只需要以不同的方式构建正则表达式:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="list">
<words>
<word>
<search>Bird</search>
<replace>Dog</replace>
</word>
<word>
<search>word</search>
<replace>man</replace>
</word>
</words>
</xsl:param>
<xsl:template match="@*|*|comment()|processing-instruction()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:variable name="search" select="concat('(',string-join($list/words/word/search,'|'),')')"/>
<xsl:analyze-string select="." regex="{$search}">
<xsl:matching-substring>
<xsl:value-of select="$list/words/word[search=current()]/replace"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
这将产生:
<something>
<parent>
<child>Dog is the man 1.</child>
<child>Curd is the man 2.</child>
<child>Nerd is the man 3.</child>
</parent>
<parent>
<child>Dog is the man 4.</child>
<child>Word is the man 5.</child>
<child>Dog is the man 6.</child>
</parent>
</something>
答案 1 :(得分:2)
这应该这样做:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:param name="findText" select="'Bird'" />
<xsl:param name="replaceText" select="'Dog'" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="." />
<xsl:with-param name="replace" select="$findText" />
<xsl:with-param name="by" select="$replaceText" />
</xsl:call-template>
</xsl:template>
<xsl:template name="string-replace-all">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$by" />
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text"
select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="by" select="$by" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
请注意,我已将'Bird'和'Dog'指定为参数的默认值,以便我可以轻松演示结果,但应该可以从外部代码传递这些参数的值。 在样本输入上运行时,会产生:
<something>
<parent>
<child>Dog is the word 1.</child>
<child>Curd is the word 2.</child>
<child>Nerd is the word 3.</child>
</parent>
<parent>
<child>Dog is the word 4.</child>
<child>Word is the word 5.</child>
<child>Dog is the word 6.</child>
</parent>
</something>
答案 2 :(得分:0)
我认为诀窍是要理解文档模型与字符串解析不同。一旦你有了这个,这个用例在XQuery或XSLT中都很容易。你自己的偏好将是一个品味问题。这是XQuery中的粗略方法。更精细的解决方案可能使用递归函数调用ala http://docs.marklogic.com/4.1/guide/app-dev/typeswitch
let $in := <something>
<parent>
<child>Bird is the word 1.</child>
<child>Curd is the word 2.</child>
<child>Nerd is the word 3.</child>
</parent>
<parent>
<child>Bird is the word 4.</child>
<child>Word is the word 5.</child>
<child>Bird is the word 6.</child>
</parent>
</something>
return element { node-name($in) } {
$in/@*,
for $n in $in/node()
return typeswitch($n)
case element(parent) return element { node-name($n) } {
for $c in $n/node()
return typeswitch($c)
case element(child) return element { node-name($c) } {
replace($c, 'Bird', 'Dog') }
default return $c }
default return $n }
答案 3 :(得分:0)
这是另一个XQuery选项......
declare function local:searchReplace($element as element()) {
element {node-name($element)}
{$element/@*,
for $child in $element/node()
return
if ($child instance of element())
then
local:searchReplace($child)
else
replace($child,'Bird','Dog')
}
};
local:searchReplace(/*)
这也产生与我的XSLT 2.0答案相同的输出:
<something>
<parent>
<child>Dog is the word 1.</child>
<child>Curd is the word 2.</child>
<child>Nerd is the word 3.</child>
</parent>
<parent>
<child>Dog is the word 4.</child>
<child>Word is the word 5.</child>
<child>Dog is the word 6.</child>
</parent>
</something>