我想从xml中删除空属性,还需要根据特定元素拆分它。我创建了两个xsl用于分割和单独删除空属性,它工作正常。但我需要结合这两个xsl,这样在删除空属性后,需要根据特定元素对xml进行拆分。
RemoveAttribute xslt:
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*[not(normalize-space(.))]">
<xsl:if test="descendant::*/@*[not(normalize-space(.))]">
<xsl:copy />
</xsl:if>
</xsl:template>
</xsl:stylesheet>
拆分XSLT:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*" >
<xsl:result-document href="ure.xml">
<xsl:element name="Employee" >
<xsl:attribute name="xsi:schemaLocation">sample.xsd</xsl:attribute>
<xsl:copy-of select="/Employee/*"/>
</xsl:element>
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>
输入XML:
<?xml version="1.0" encoding="UTF-8"?>
<Enroll>
<Department id="x1" name="">
<members id ="" name="lio">ds</members>
</Department>
<Employee>
<address id="s1" no=""></address>
<domain id="" no="34"></domain>
</Employee>
</Enroll>
output_one xml:
<Department id="x1" name="">
<members id ="" name="lio">ds</members>
</Department>
输出+ _two Xml:
<Employee>
<address id="s1" ></address>
<domain no="34"></domain>
</Employee>
输出应该是一个两个独立的xml文件,应该有分割的xml部分,需要删除空属性。
我尝试过使用Apply-templates,include和xml pipelining,但是我无法使用它。
非常感谢任何帮助。
答案 0 :(得分:2)
这应该完成你所描述的内容:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exclude-result-prefixes="xsi">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Employee//@*[not(normalize-space())]" />
<xsl:template match="/*" >
<xsl:result-document href="output_one.xml">
<xsl:apply-templates select="Department" />
</xsl:result-document>
<xsl:result-document href="output_two.xml">
<xsl:apply-templates select="Employee" />
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>
在提供的输入上运行时,结果为:
output_one.xml:
<Department id="x1" name="">
<members id="" name="lio">ds</members>
</Department>
output_two.xml:
<Employee>
<address id="s1" />
<domain no="34" />
</Employee>
答案 1 :(得分:2)
我将提供一个XProc替代方案,因为您使用XProc标记了问题。以下内容保留了Employee元素:
<p:declare-step version="1.0" xmlns:p="http://www.w3.org/ns/xproc">
<p:input port="source"/>
<p:output port="result"/>
<p:delete match="@*[normalize-space(.) = '']"/>
<p:filter select="//Employee"/>
</p:declare-step>
您可以使用命令行执行XMLCalabash,如:
calabash --input source=in.xml --output result=employee.xml test.xpl
它确实假设您的输入中只有一个Employee元素。否则,它将尝试将多个Employee元素写入单个文件。它首先会抱怨结果输出端口不接受序列。
如果你向它添加sequence="true"
而没有任何进一步的更改,你将得到非格式良好的XML,就像JLRishe的XSLT方法一样。在这种情况下,您需要使用p:wrap-sequence
包装Employee元素序列,或者使用p:for-each
,以及p:store
之类的内容将各个员工写入磁盘。
注意:如果您是XProc的新手,最后一段可能有点简洁。如果我需要详细说明,请告诉我。
<强>增加:强>
如果要使用XProc保存Department和Employee元素,可以使用以下命令:
<p:declare-step version="1.0" xmlns:p="http://www.w3.org/ns/xproc">
<p:input port="source"/>
<p:output port="employees">
<p:pipe step="employees" port="result"/>
</p:output>
<p:output port="departments" primary="true"/>
<p:delete match="@*[normalize-space(.) = '']" name="cleaned"/>
<p:filter select="//Employee"/>
<p:wrap-sequence wrapper="Employees" name="employees"/>
<p:filter select="//Department">
<p:input port="source">
<p:pipe step="cleaned" port="result"/>
</p:input>
</p:filter>
<p:wrap-sequence wrapper="Departments"/>
</p:declare-step>
您可以使用命令行执行XMLCalabash,如:
calabash --input source=in.xml --output employees=employees.xml --output departments.xml test2.xpl
代码仍然遵循相同的流程,但员工输出端口是非主要的,并且必须明确绑定到employees步骤的结果。部门过滤使用显式输入端口绑定,不将“员工”的结果作为输入,而是使用“已清理”步骤。所有其他输入和输出都根据约定自动绑定。
注意:我添加了p:wrap-sequence
以使其更强大。如果您将员工的名称属性从p:wrap-sequence
移至其前面的p:filter
,则可以将其删除。
HTH!