0

我正在转换不包含架构中每个元素的 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>
4

2 回答 2

0

Right. Well, it's nice to know that your schema is written in a proprietary schema language of your own invention. I suppose we have to guess the semantics, but they seem straightforward enough. As it seems this schema language can only express sequence, and not choice or iteration, the problem might be rather simpler than it would be with a more conventional schema language.

It seems to me that the rule you want to apply is:

To process an element E named N in the instance, find the element S named N in the schema. For each child SC of that schema element, if E has a child EC with the same name, process EC, otherwise copy SC.

That translates to this:

<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>

Not tested.

于 2013-06-18T22:10:16.780 回答
0

没有简单的答案。只需编写一个输出有效 XML 的转换。

周围有一些映射工具,例如来自 Altova,它们试图自动化创建从模式 A 转换为模式 B 的样式表的任务。我从未发现它们非常有用,但它们可能对您有用。

于 2013-06-18T09:29:46.350 回答