【问题标题】:XSL transformation where input xml file has xmlns defined or absent输入 xml 文件定义或不存在 xmlns 的 XSL 转换
【发布时间】:2014-01-17 18:13:52
【问题描述】:

我有一个 xml 输入,有时可能有也可能没有定义 xmlns。 如何解决这种情况,只需一个 xsl 即可成功转换? 以下是两种情况下的输入和 xsl (1.0)

输入文件:

<?xml version="1.0" encoding="UTF-8"?>
<input version="2.1">
    <Data>
        <Object class="PM" operation="create" name="japan">
            <p name="Active">1</p>
        </Object>
        <Object class="AM" operation="create" name="india">
            <p name="Active">0</p>
        </Object>
    </Data>
</input>

没有命名空间定义的 XSL:

<?xml version="1.0"?>
<xsl:stylesheet
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   version="1.0">
    <xsl:template match="Data">
        <xsl:copy>
            <xsl:apply-templates select="Object[@class='PM' or @class='AM']">
                <xsl:sort select="@name"/>
            </xsl:apply-templates>
            <xsl:apply-templates select="Object[not(@class='PM' or @class='AM')]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Object[@operation = 'create' ]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:attribute name="class">
                <xsl:value-of select="concat(@class,'/TIME')"/>
            </xsl:attribute>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

定义命名空间的输入xml:

<?xml version="1.0" encoding="UTF-8"?>
<input version="2.1" xmlns="xyz.xsd">
    <Data>
        <Object class="PM" operation="create" name="japan">
            <p name="Active">1</p>
        </Object>
        <Object class="AM" operation="create" name="india">
            <p name="Active">0</p>
        </Object>
    </Data>
</input>

虽然 xslt 没有抛出错误,但输出并没有按预期转换:(

欢迎使用单个 xsl 或任何想法来处理上述情况。

【问题讨论】:

  • 它是一个特定的命名空间,可以存在也可以不存在 - 或者他们可以向你抛出任何随机命名空间?
  • 是的,目前只有一个命名空间或者它不存在..还没有遇到随机的..

标签: xml xslt xslt-1.0


【解决方案1】:

如果您需要处理具有特定本地名称的任何元素,而不考虑 XSLT 1.0 中的命名空间,那么您需要使用像 *[local-name() = 'Object'] 这样的惯用语,或者您可以将模式基于结构而不是名称(即而不是“匹配一个名为 Object 的元素”,您说的是“匹配任何从根目录向下三层的元素”):

<?xml version="1.0"?>
<xsl:stylesheet
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   version="1.0">
    <xsl:template match="/*/*">
        <xsl:copy>
            <xsl:apply-templates select="*[@class='PM' or @class='AM']">
                <xsl:sort select="@name"/>
            </xsl:apply-templates>
            <xsl:apply-templates select="*[not(@class='PM' or @class='AM')]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="/*/*/*[@operation = 'create' ]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:attribute name="class">
                <xsl:value-of select="concat(@class,'/TIME')"/>
            </xsl:attribute>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

【讨论】:

    【解决方案2】:

    编写您的 XSLT,以便在输入不在命名空间中时它所做的第一件事是创建位于命名空间中的数据的副本(反之亦然)。那么剩下的代码就不用担心区分了。

    【讨论】:

    • 嗨迈克尔...已经存在的框架没有提供创建另一个输入数据副本的选项..
    • 什么?我以为你在使用 XSLT?
    • 抱歉,我的意思是输入是固定的,我只能在对输入执行必要的逻辑时使用 xslt。
    • @user1529282 我认为 Michael 暗示的是一个两阶段的转换——首先去除命名空间,将结果存储在一个变量中,然后使用 &lt;xsl:apply-templates select="exslt:node-set($resultOfPhase1)"/&gt; 应用你的主模板。如果您搜索 Stack Overflow,您会找到可以从中学习的这种技术的示例。
    【解决方案3】:

    是的,目前只有一个命名空间或者它不存在.. 还没有 遇到随机的。

    在这种情况下,您可以为命名空间定义一个前缀,并调整您的样式表以“并行”调用任何元素的两个版本:

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xyz="http://xyz.xsd">
    
    <xsl:template match="Data | xyz:Data">
        <xsl:copy>
            <xsl:apply-templates select="Object[@class='PM' or @class='AM'] | xyz:Object[@class='PM' or @class='AM']">
                <xsl:sort select="@name"/>
            </xsl:apply-templates>
            <xsl:apply-templates select="Object[not(@class='PM' or @class='AM')] | Object[not(@class='PM' or @class='AM')]"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="Object[@operation = 'create' ] | Object[@operation = 'create' ]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:attribute name="class">
                <xsl:value-of select="concat(@class,'/TIME')"/>
            </xsl:attribute>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-27
      • 2015-09-23
      • 2016-02-12
      • 1970-01-01
      相关资源
      最近更新 更多