我正在转换不包含架构中每个元素的XML文件。我应该在XSLT文件中使用什么技术,以便生成的XML包含模式中指定的所有元素?
我知道XSLT 2.0很可能很容易解决这个问题,但我仍然坚持使用XSLT 1.0。
保
这是我想要做的一个例子:
Schema.xml的
<SAN>
<STACKMEMBERS>
<STACKMEMBER>
<A/>
<B/>
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<C/>
<D/>
<E/>
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
</STACKMEMBERS>
</SAN>
DataFile.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))。我觉得我离这里很近,但需要一点点推动才能获得所需的输出。
保
以下是使用Michael Kay的模板修改的完整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: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>
答案 0 :(得分:0)
没有简单的答案。只需编写一个输出有效XML的转换。
周围有映射工具,例如来自Altova,尝试自动完成创建从模式A转换为模式B的样式表的任务。我从未发现它们非常有用,但它们可能适合您。
答案 1 :(得分:0)
右。嗯,很高兴知道你的模式是用你自己发明的专有模式语言编写的。我想我们必须猜测语义,但它们看起来很简单。由于这种模式语言似乎只能表达序列,而不是选择或迭代,因此问题可能比使用更传统的模式语言更简单。
在我看来,您想要应用的规则是:
要在实例中处理名为N的元素E,请在架构中找到名为N的元素S.对于该模式元素的每个子SC,如果E具有相同名称的子EC,则处理EC,否则复制SC。
这意味着:
<xsl:variable name="Instance" select="/"/>
<xsl:variable name="Schema" select="doc('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>
未经测试。