我有一个源XML文档,看起来像这样:
<root>
<users>
<user id="1" name="user 1" />
<user id="2" name="user 2" />
<user id="3" name="user 3" />
</users>
<posts>
<post>
<user>1</user>
<text>First sample post!</text>
<status>DELETED</status>
</post>
<post>
<user>2</user>
<text>Second sample post!</text>
<status>ACTIVE</status>
</post>
<post>
<user>3</user>
<text>Third sample post!</text>
<status>DELETED</status>
</post>
</posts>
</root>
我需要过滤用户,以便目标文档只包含ACTIVE帖子和post元素中引用的那些用户。:
<root>
<users>
<user id="2" name="user 2" />
</users>
<posts>
<post>
<user>2</user>
<text>Second sample post!</text>
</post>
</posts>
</root>
我无权更改源文档,我需要使用XSLT(我很新)来实现这一点。
我可以轻松过滤帖子,但我不确定如何建立用户列表。
在我走得更远之前,我想检查一下是否可行。
干杯
答案 0 :(得分:1)
是的,可以使用这样的样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- Copy asnything not overridden below -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Copy <user> if active <post> exists -->
<xsl:template match="users/user"><!-- don't match 'post/user' -->
<xsl:variable name="userId" select="@id"/>
<xsl:if test="../../posts/post[user = $userId][status = 'ACTIVE']">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
<!-- Copy <post> if active -->
<xsl:template match="post">
<xsl:if test="status = 'ACTIVE'">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
<!-- Don't copy <status> -->
<xsl:template match="status">
</xsl:template>
</xsl:stylesheet>
测试
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(new File("test.xslt")));
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(new StreamSource(new File("test.xml")),
new StreamResult(System.out));
输出
<root>
<users>
<user id="2" name="user 2"/>
</users>
<posts>
<post>
<user>2</user>
<text>Second sample post!</text>
</post>
</posts>
</root>
答案 1 :(得分:1)
首先,您应该了解身份模板
post
它本身将完全从源文档复制到所有节点。
这意味着,不是根据您需要复制的内容进行思考,而是根据您不需要复制的内容进行思考。这是通过添加覆盖身份模板的具有更高优先级的模板来实现的。
您不希望status
元素在<xsl:template match="post[status!='ACTIVE']" />
不是“有效”的情况下?只需要一个空模板来阻止它们被复制。
status
同样,要删除<xsl:template match="status" />
节点本身(对于它复制的帖子)
user
对于xsl:key
元素,请考虑使用post
查找<xsl:key name="posts" match="post" use="user" />
个元素
<xsl:template match="user[key('posts', @id)/status!='ACTIVE']" />
然后,忽略用户的模板就是这个....
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:key name="posts" match="post" use="user" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="post[status!='ACTIVE']" />
<xsl:template match="status" />
<xsl:template match="user[key('posts', @id)/status!='ACTIVE']" />
</xsl:stylesheet>
把这一切放在一起给你这个......
{{1}}