以下是XML结构 -
<Docs>
<Doc>
<P>blah blah blah<pg>1</pg>blah blah</P>
<P>blah blah blah<pg>2</pg>blah blah</P>
</Doc>
<Doc>
<P>blah blah blah<pg>3</pg>blah blah</P>
<P>blah blah blah<pg>4</pg>blah blah</P>
</Doc>
</Docs>
我想删除pg
节点中的P
节点,并将其插入P
节点的兄弟节点。
像这样 -
<Docs>
<Doc>
<P>blah blah blah</P>
<pg>1</pg>
<P>blah blah</P>
<P>blah blah blah</P>
<pg>2</pg>
<P>blah blah</P>
</Doc>
<Doc>
<P>blah blah blah</P>
<pg>3</pg>
<P>blah blah</P>
<P>blah blah blah</P>
<pg>4</pg>
<P>blah blah</P>
</Doc>
</Docs>
如何完成它?
答案 0 :(得分:3)
这是一个XSLT选项...
XML输入
<Docs>
<Doc>
<P>blah blah blah<pg>1</pg>blah blah</P>
<P>blah blah blah<pg>2</pg>blah blah</P>
</Doc>
<Doc>
<P>blah blah blah<pg>3</pg>blah blah</P>
<P>blah blah blah<pg>4</pg>blah blah</P>
</Doc>
</Docs>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="P">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="P/text()">
<P><xsl:value-of select="."/></P>
</xsl:template>
</xsl:stylesheet>
XML输出
<Docs>
<Doc>
<P>blah blah blah</P>
<pg>1</pg>
<P>blah blah</P>
<P>blah blah blah</P>
<pg>2</pg>
<P>blah blah</P>
</Doc>
<Doc>
<P>blah blah blah</P>
<pg>3</pg>
<P>blah blah</P>
<P>blah blah blah</P>
<pg>4</pg>
<P>blah blah</P>
</Doc>
</Docs>
答案 1 :(得分:2)
如果您支持XQuery Update,这是一个XQuery解决方案。
for $p in $c//P (: for each paragraph tag :)
return (
for $node in $p/(text(), pg) (: find all subnodes :)
return (
let $node :=
if ($node/self::text())
then element P { $node } (: wrap text nodes in new paragraph tags :)
else $node
return insert node $node after $p (: insert the node after the old paragraph tag :)
),
delete node $p (: drop the old paragraph tag :)
)
刚刚实现了一个版本没有 XQuery Update(只返回结果)更短:
element Docs {
element Doc {
for $node in //P/(text(), pg)
return
if ($node/self::text())
then element P { $node }
else $node
}
}
答案 2 :(得分:2)
XSLT看起来确实更适合这项任务。 XSLT 2.0提供了xsl:for-each-group
功能,在这里非常有用。它比仅仅匹配P内的text()节点更健壮。如果P元素在pg标记旁边包含其他内联元素,那肯定会有所帮助。
这是2.0解决方案,Daniel Haley稍微改变了解决方案:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="P">
<xsl:variable name="P" select="."/>
<xsl:for-each-group select="node()" group-starting-with="pg">
<xsl:apply-templates select="self::pg"/>
<xsl:element name="{node-name($P)}">
<xsl:apply-templates select="$P/@*|current-group()[not(self::pg)]"/>
</xsl:element>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
HTH!
答案 3 :(得分:1)
xquery version "3.0";
let $xml :=
<Docs>
<Doc>
<P>blah blah blah<pg>1</pg>blah blah</P>
<P>blah blah blah<pg>2</pg>blah blah</P>
</Doc>
<Doc>
<P>blah blah blah<pg>3</pg>blah blah</P>
<P>blah blah blah<pg>4</pg>blah blah</P>
</Doc>
</Docs>
return
<Docs>{
for $doc in $xml/Doc
return
<Doc>{
for $P in $doc/P
return
for tumbling window $w in $P/node()
start when true()
end next $e
when $e instance of element(pg)
return (
$w[self::pg],
<P>{
$w[not(self::pg)]
}</P>
)
}</Doc>
}</Docs>
它确实需要一个支持3.0的XQuery处理器,包括这些翻滚窗口。 Zorba是一个很好的例子,您可以在http://try.zorba.io
在线测试此代码HTH!