我们有一个生成不需要的XML元素的工具,我们正在使用XSLT将其转换为所需的格式。
我们正在为该文件生成的每个XML编写不同的XSLT。例如一个用于Customers XML,一个用于Orders XML,依此类推。
下面是该工具生成的几个XML数据文件和预期的实际输出
客户
工具生成的XML
<Message>
<Data>
<CustomerArray>
<Customer>
<X>
<Name>John</Name>
<Id>100</Id>
<Roles>
<Role>
<X>Manager</X>
<X>Architect</X>
</Role>
</Roles>
</X>
<X>
<Name>Doe</Name>
<Id>102</Id>
<Roles>
<Role>
<X>Supervisor</X>
<X>Admin</X>
</Role>
</Roles>
</X>
</Customer>
</CustomerArray>
</Data>
</Message>
必需的XML数据
<Message>
<Data>
<CustomerArray>
<Customer>
<Name>John</Name>
<Id>100</Id>
<Roles>
<Role>Manager</Role>
<Role>Architect</Role>
</Roles>
</Customer>
<Customer>
<Name>Doe</Name>
<Id>102</Id>
<Roles>
<Role>Supervisor</Role>
<Role>Admin</Role>
</Roles>
</Customer>
</CustomerArray>
</Data>
</Message>
订单
工具生成的XML
<Message>
<Orders>
<Order>
<X>
<OrderNumber>O123</OrderNumber>
<CustomerID>C100</CustomerID>
<Quantity>100</Quantity>
<UnitPrice>10.0</UnitPrice>
</X>
<X>
<OrderNumber>O456</OrderNumber>
<CustomerID>C107</CustomerID>
<Quantity>100</Quantity>
<UnitPrice>5.0</UnitPrice>
</X>
</Order>
</Orders>
</Message>
必需的XML数据
<Message>
<Orders>
<Order>
<OrderNumber>O123</OrderNumber>
<CustomerID>C100</CustomerID>
<Quantity>100</Quantity>
<UnitPrice>10.0</UnitPrice>
</Order>
<Order>
<OrderNumber>O456</OrderNumber>
<CustomerID>C107</CustomerID>
<Quantity>100</Quantity>
<UnitPrice>5.0</UnitPrice>
</Order>
</Orders>
</Message>
不需要的元素X
可以来自任何级别。
是否可以编写通用XSLT转换以在所有XML输入中实现此结果?例如,在找到X
的地方,将其替换为父标记,然后删除父标记。
答案 0 :(得分:2)
您需要为具有任何X
子节点的所有节点编写带有显式模板的标识转换,以便可以复制它们。
这个变换符合你的要求。它使用变量name
来保存X
父元素的名称,以避免在生成每个输出元素时编写更加模糊的name(current())
。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes" encoding="UTF-8" omit-xml-declaration="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[X]">
<xsl:variable name="name" select="name()"/>
<xsl:for-each select="X">
<xsl:element name="{$name}">
<xsl:apply-templates/>
</xsl:element>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
<强>输出强>
客户
<Message>
<Data>
<CustomerArray>
<Customer>
<Name>John</Name>
<Id>100</Id>
<Roles>
<Role>Manager</Role>
<Role>Architect</Role>
</Roles>
</Customer>
<Customer>
<Name>Doe</Name>
<Id>102</Id>
<Roles>
<Role>Supervisor</Role>
<Role>Admin</Role>
</Roles>
</Customer>
</CustomerArray>
</Data>
</Message>
订单的
<Message>
<Orders>
<Order>
<OrderNumber>O123</OrderNumber>
<CustomerID>C100</CustomerID>
<Quantity>100</Quantity>
<UnitPrice>10.0</UnitPrice>
</Order>
<Order>
<OrderNumber>O456</OrderNumber>
<CustomerID>C107</CustomerID>
<Quantity>100</Quantity>
<UnitPrice>5.0</UnitPrice>
</Order>
</Orders>
</Message>
答案 1 :(得分:1)
这是一个稍微简单/更短的解决方案,当X
可以包含非X
兄弟元素时,它也能正确处理:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[X]"><xsl:apply-templates/></xsl:template>
<xsl:template match="X">
<xsl:element name="{name(..)}">
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
当此转换应用于以下XML文档时(第一个提供的文档,其中一个非X
兄弟添加到X
元素:
<Message>
<Data>
<CustomerArray>
<Customer>
<X>
<Name>John</Name>
<Id>100</Id>
<Roles>
<Role>
<X>Manager</X>
<X>Architect</X>
</Role>
</Roles>
</X>
<somethingElse/>
<X>
<Name>Doe</Name>
<Id>102</Id>
<Roles>
<Role>
<X>Supervisor</X>
<X>Admin</X>
</Role>
</Roles>
</X>
</Customer>
</CustomerArray>
</Data>
</Message>
产生了想要的正确结果:
<Message>
<Data>
<CustomerArray>
<Customer>
<Name>John</Name>
<Id>100</Id>
<Roles>
<Role>Manager</Role>
<Role>Architect</Role>
</Roles>
</Customer>
<somethingElse/>
<Customer>
<Name>Doe</Name>
<Id>102</Id>
<Roles>
<Role>Supervisor</Role>
<Role>Admin</Role>
</Roles>
</Customer>
</CustomerArray>
</Data>
</Message>
请注意,Borodin的解决方案会丢失somethingElse
元素。