[英]How to change XML attributes to elements then move them to different node?
我想将<Card>
元素( id
, status
, type
)的属性转换为关联的<Information>
元素的子元素。 我已经实现了属性->元素更改,但是如何为生成的元素提供正确的父元素?
这是一个示例输入文件:
<?xml version="1.0" encoding="UTF-8"?>
<Customers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" hasMore="false"
recordCount="1" responseTime="2017-04-27T19:35:02" returnCode="SUCCESS">
<Customer>
<Information>
<FirstName>Brandon</FirstName>
<MiddleName/>
<LastName>Wrong</LastName>
<CustomerStatus>ACTIVE</CustomerStatus>
<Household>false</Household>
<EnrollmentDate xsi:nil="true"/>
<Address>100 Broadway Ave</Address>
<City>San Gabriel</City>
<State>CA</State>
<ZIP>91776-2348</ZIP>
<Country/>
<Phone>6268881212</Phone>
<MobilePhone/>
<Email>BWrong1@gmail.com</Email>
<DateOfBirth xsi:nil="true"/>
</Information>
<Cards>
<Card id="40012345601" status="ACTIVE" type="Customer card"/>
</Cards>
</Customer>
</Customers>
这是我当前的样式表:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
<xsl:output indent="yes" method="xml" encoding="utf-8" omit-xml-declaration="yes"/>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="Customers/@hasMore|Customers/@recordCount|Customers/@returnCode|@xsi:nil|@responseTime" />
<xsl:template match="Card/@*">
<xsl:element name="{local-name(.)}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="comment() | text() | processing-instruction()">
<xsl:copy/>
</xsl:template>
</xsl:stylesheet>
当您根据移动节点来完成这项工作时,您的想法是无益的。 XSL不会更改 (或移动等)任何东西。 相反,它根据输入文档的特征来定义结果文档。
由于定义输出文档元素的一部分就是定义其内容,因此必须在该输出节点的模板上下文中定义输出元素的子节点。 因此,对于您的特殊情况,您需要一个比<Information>
元素更为具体的模板,而不是您现在正在使用的身份转换。
但是,在继续进行详细介绍之前,我会注意到,您定义的身份转换(因为它分布在三个单独的模板上,并且仅使用元素和属性的本地名称进行了扩展)比没有身份验证的规范身份转换更为冗长明显的理由或优势。 这是通常的身份转换,全部在一个模板中:
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
但是,您似乎要禁止显示除名称空间声明和要转换为元素的属性以外的所有属性。 在那种情况下,与其提供显式抑制属性的模板,不如仅仅通过在身份转换上使用(仅)此变体来避免首先转换属性:
<xsl:template match="node()">
<xsl:copy>
<!-- transform child nodes, except attributes -->
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
您不需要使用这种方法来保留名称空间声明的特殊条款,因为xsl:copy
自动复制复制的节点的名称空间节点,从而需要提供名称空间声明。
这样一来,可以将<Information>
元素的所需模板写为标识模板的变体:
<xsl:template match="Information">
<xsl:copy>
<!-- transform all the element's child nodes -->
<xsl:apply-templates select="node()"/>
<!-- include also transformations of the associated <Card> attributes -->
<xsl:apply-templates select="../Cards/Card/@*" />
</xsl:copy>
</xsl:template>
尽管尚不清楚为什么使用local-name()
而不是name()
,但您已经具有<Card>
属性的模板可能会做。 但是,您似乎确实希望避免在输出文档中发出看似无信息的<Cards>
和<Card>
元素。 您可以通过提供<Cards>
的模板将其转换为空的方法来实现:
<xsl:template match="Cards"/>
然后,将所有这些放在一起,您可能会得到如下结果:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml" encoding="utf-8"
omit-xml-declaration="yes"/>
<!-- attributes are not matched or selected for transformation by this
template: -->
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<!-- Information elements require a special template: -->
<xsl:template match="Information">
<xsl:copy>
<!-- transform all the element's child nodes -->
<xsl:apply-templates select="node()|@*"/>
<!-- include also transformations of the associated <Card> attributes -->
<xsl:apply-templates select="../Cards/Card/@*" />
</xsl:copy>
</xsl:template>
<!-- transform <Cards> elements to nothing -->
<xsl:template match="Cards"/>
<!-- applied only where matching attribute nodes are selected for
transformation: -->
<xsl:template match="Card/@*">
<xsl:element name="{name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.