我正在转换不包含架构中每个元素的 XML 文件。我应该在我的 XSLT 文件中使用什么技术,以便生成的 XML 包含架构中指定的所有元素?
我知道 XSLT 2.0 可能很容易解决这个问题,但我坚持使用 XSLT 1.0。
保罗
这是我正在尝试做的一个例子:
架构.xml
<SAN>
<STACKMEMBERS>
<STACKMEMBER>
<A/>
<B/>
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<C/>
<D/>
<E/>
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
</STACKMEMBERS>
</SAN>
数据文件.xml
<SAN>
<STACKMEMBERS>
<STACKMEMBER>
<A>1111</A>
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<D>3333</D>
<E>4444</E>
</ETHERNETSWITCH>
<ETHERNETSWITCH>
<D>5555</D>
<E>6666</E>
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
<STACKMEMBER>
<A>2222</A>
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<D>7777</D>
<E>8888</E>
</ETHERNETSWITCH>
<ETHERNETSWITCH>
<D>9999</D>
<E>1010</E>
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
</STACKMEMBERS>
</SAN>
期望的输出:
<SAN>
<STACKMEMBERS>
<STACKMEMBER>
<A>1111</A>
<B />
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<C />
<D>3333</D>
<E>4444</E>
</ETHERNETSWITCH>
<ETHERNETSWITCH>
<C />
<D>5555</D>
<E>6666</E>
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
<STACKMEMBER>
<A>2222</A>
<B />
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<C />
<D>7777</D>
<E>8888</E>
</ETHERNETSWITCH>
<ETHERNETSWITCH>
<C />
<D>9999</D>
<E>1010</E>
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
</STACKMEMBERS>
</SAN>
我当前的 XSLT 文件是...
<?xml version="1.0" encoding="windows-1252"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="schemaFile" select="document('Schema.xml')"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<SAN>
<STACKMEMBERS>
<xsl:for-each select="/SAN/STACKMEMBERS/STACKMEMBER">
<xsl:copy-of select="."/>
<xsl:copy-of select="$schemaFile/SAN/STACKMEMBERS/STACKMEMBER"/>
</xsl:for-each>
</STACKMEMBERS>
</SAN>
</xsl:template>
</xsl:stylesheet>
...它给了我错误的结果:
<SAN>
<STACKMEMBERS>
<STACKMEMBER>
<A>1111</A>
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<D>3333</D>
<E>4444</E>
</ETHERNETSWITCH>
<ETHERNETSWITCH>
<D>5555</D>
<E>6666</E>
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
<STACKMEMBER>
<A />
<B />
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<C />
<D />
<E />
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
<STACKMEMBER>
<A>2222</A>
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<D>7777</D>
<E>8888</E>
</ETHERNETSWITCH>
<ETHERNETSWITCH>
<D>9999</D>
<E>1010</E>
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
<STACKMEMBER>
<A />
<B />
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<C />
<D />
<E />
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
</STACKMEMBERS>
</SAN>
请注意,元素 B 和 C 在模式中定义,但不存在于数据文件中。所需的输出会将仅包含在模式中的元素添加到数据文件中。
最好有多个选择标准(如 select=(one, two))。我觉得我在这里很近,但需要一点点推动才能获得所需的输出。
保罗
下面是完整的 XSLT 文件,使用 Michael Kay 的模板进行了修改,但不太有效:
<?xml version="1.0" encoding="windows-1252"?>
<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:variable name="Instance" select="/"/>
<xsl:variable name="Schema" select="document('schema.xml')"/>
<xsl:template match="*">
<xsl:copy>
<xsl:variable name="E" select="."/>
<xsl:variable name="S" select="$Schema//*[name(.)=name($E)]"/>
<xsl:for-each select="$S/*">
<xsl:variable name="SC" select="."/>
<xsl:variable name="EC" select="$E/*[name(.)=name($SC)]"/>
<xsl:choose>
<xsl:when test="$EC">
<xsl:apply-templates select="$EC"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$SC"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我编写了一个应该返回元素的 XPath 的模板。然后我修改了上面的模板,通过 XPath 而不是元素名称来查找元素。结果是堆栈溢出,我不知道我哪里出错了。
这是不起作用的 XSLT 代码。任何帮助将非常感激。
保罗
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/2011-03-16T10:53:27">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="Data" select="/"/>
<xsl:variable name="Schema" select="document('MainDataSource.xml')"/>
<xsl:template match="*[not(*)]">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template name="GetXPath">
<xsl:param name="element"/>
<xsl:if test="not(*)">
<xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
</xsl:if>
</xsl:template>
<xsl:template match="*" mode="path">
<xsl:value-of select="concat('/',name())"/>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:variable name="DataElement" select="."/>
<xsl:variable name="DataElementXPath">
<xsl:call-template name="GetXPath">
<xsl:with-param name="element" select="$DataElement"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="SchemaElement" select="$Schema/*[$DataElementXPath]"/>
<xsl:for-each select="$SchemaElement/*">
<xsl:variable name="SchemaChild" select="."/>
<xsl:variable name="SchemaChildXPath">
<xsl:call-template name="GetXPath">
<xsl:with-param name="element" select="$SchemaChild"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="DataChild" select="$Data/*[$SchemaChildXPath]"/>
<xsl:choose>
<xsl:when test="$DataChild">
<xsl:apply-templates select="$DataChild"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$SchemaChild"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>