【问题标题】:Is it possible or how to further DRY this XML statement?是否有可能或如何进一步干燥这个 XML 语句?
【发布时间】:2014-06-20 04:55:08
【问题描述】:

从其他人的经验来看,似乎是个案,他们的问题通常是如何干燥这个或如何干燥那个......所以在我的情况下,它是类似的,而不是对于一个特殊情况,我尝试更笼统地问:

说,我有一个带有以下几行的 xml 代码

<input type="text" defaultValue="" name="Fax_Label" label="Fax Label" />

将被解析,然后使用 XSLT 进行样式化。

因为我来自更像 CSS、PHP、JS,基于我的 php 经验 我可以创建一个这样的数组和一个循环来完成,这样我就可以将参数与模板块分开,例如。

$para_arr = array(
   // type | name | label
   array('text', 'Fax_Text', 'Fax Text')
);

for( $i=0; $i<count($para_arr); $i++){
echo '<input type="{$para_arr[i][0]}" defaultValue="" name="{$para_arr[i][1]}" label="{$para_arr[i][2]}" />';
}

是否有任何 XML 等效的方法来完成相同的事情? 非常感谢。

以上内容将成为该问题历史的一部分,并让其他人知道为什么我被否决了。 老问题:如何像 PHP 一样使用数组和 for 循环来干燥 XML/XSLT?

此处修改问题: 可以干燥这个结构吗? 因为会有超过 30 个字段,所以要全部复制粘贴并逐个编辑,非常繁琐且难以维护。

<namespace>
    <cms_data>
        <inputGRP>
            <input type="text" defaultValue="" name="nickname_label" label="NickName Label" />
            <input type="text" defaultValue="" name="nickname_error" label="NickName Error" />
            <input type="text" defaultValue="" name="rowTitle_login" label="Row Heading Login" />
            <input type="text" defaultValue="" name="title_label" label="Title Label" />
            <input type="text" defaultValue="" name="title_error" label="Title Error" />
        </inputGRP>
    </cms_data>
</namespace>

【问题讨论】:

  • 很难给出具体的答案,因为问题不够具体。一般来说,XSLT 在 XML 被解析之后就可以与 XML 一起工作——所以这项工作已经为您完成了。
  • 您生成一个 XML(例如使用 DOM)。 Xslt 从 DOM 读取值并对其进行转换。
  • 感谢您的评论,我试图更具体地更改问题。也许我应该多放一些我打算实现的sn-ps。
  • 我仍然不知道你的问题是什么。 XSLT 不是 PHP。不问如何在 XSLT 中使用 PHP 工具;询问如何在 XSLT 中完成任务。
  • 我明白你的意思,嗯,这可能是因为我的想法是基于我的母语(显然不是英语)所以我想表达类似“如何通过与另一个类比来完成这项任务我知道的编程语言”,我会在当前工作之后尽快完善问题和内容。非常感谢您的宝贵时间。

标签: xml xslt dry


【解决方案1】:

我将您的问题读作“知道如何将 PHP 变量放入 HTML 回显,这是如何在 XSLT 代码中完成的,例如在循环内”。
要在 XSLT 中输出 XML 数据,可以使用 where data 是 XML 文件中实际数据的 xpath 或 XSLT 变量。这在 HTML 属性中不起作用,因为那里不允许使用尖括号。相反,您可以使用属性值模板(AVT,请参阅http://www.w3.org/TR/xslt#attribute-value-templates),写为 {data} 就像您的 PHP 示例仅使用 xpath(或 xslt 变量)。
如果我没有抓住重点,请不要开枪,我的母语不是英语。

【讨论】:

  • 你的评论很棒,我把标题改的更具体
【解决方案2】:

我不完全确定这是否是您所要求的,但 XSLT 本身并没有数组的概念。但是,您可以像这样定义一些 XML

<array>
    <array>
        <value>text</value>
        <value>Fax_Label</value>
        <value>Fax Label</value>
    </array>
</array>

然后,对于您的“循环”,您将采用基于模板的方法,因此请选择“数组”元素

    <xsl:variable name="para_arr" select="/array" />
    <xsl:apply-templates select="$para_arr/array" />

那么模板本身会是这样的

<xsl:template match="array">
    <input type="{value[1]}" defaultValue="" name="{value[2]}" label="{value[3]}" />
</xsl:template>

注意此处使用属性值模板来输出值。花括号表示要计算的表达式,而不是字面输出。另请注意,在 XSLT 中,索引从 1 开始,而不是 0。

如果你像这样定义你的 XML 会更好

<array>
    <array>
        <value name="type">text</value>
        <value name="name">Fax_Label</value>
        <value name="label">Fax Label</value>
    </array>
</array>

然后你的 XSLT 可以被修改以处理无限数量的属性

试试这个 XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output indent="yes"/>
    <xsl:template match="/">
        <xsl:variable name="para_arr" select="/array" />

        <xsl:apply-templates select="$para_arr/array" />
    </xsl:template>

    <xsl:template match="array">
        <input defaultvalue="">
            <xsl:apply-templates select="value" />
        </input>
    </xsl:template>

    <xsl:template match="value">
        <xsl:attribute name="{@name}">
            <xsl:value-of select="." />
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

请注意,上面的 XML 可以放置在与您正在转换的主要 XML 不同的文件中,在这种情况下,只需使用 document 函数来访问它:

<xsl:variable name="para_arr" select="document('myArray.xml')/array" />

【讨论】:

  • 我会尝试,因为我被抛出这个编程领域。我将从头开始设置 iis,通过 .Net、C#、XML 和 XSLT 处理了解整个开发领域。我一定会检查一下,尝试并反馈。非常感谢。
  • @simongcc 那么,您是否可能忘记“检查”?蒂姆的代码是解决方案吗?如果是,请接受他的回答。
【解决方案3】:

XSLT 拥有的最接近数组的结构是序列。一系列原子值(如字符串)是基本的,因此您需要提出自己的方案来重现多维数组之类的东西。

这是我有 2 个序列的示例。第一个序列是属性名称。第二个序列是值。

第二个序列还需要指定它属于哪个entry。为了处理这个问题,我为每个值添加了前缀e#:。例如,第一个 entry 的条目具有前缀 e1:。然后我可以使用这些值将所有内容组合在一起。

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="names" select="('type','defaultValue','name','label')"/>
    <xsl:param name="values" select="('e1:text','e1:','e1:nickname_label','e1:NickName Label',
                                      'e2:text','e2:','e2:nickname_error','e2:NickName Error',
                                      'e3:text','e3:','e3:rowTitle_login','e3:Row Heading Login',
                                      'e4:text','e4:','e4:title_label','e4:Title Label',
                                      'e5:text','e5:','e5:title_error','e5:Title Error'
                                      )"/>

    <xsl:template match="/">
        <namespace>
            <cms_data>
                <inputGRP>            
                    <xsl:for-each-group select="$values" group-by="tokenize(.,':')[1]">
                        <input>
                            <xsl:for-each select="current-group()">
                                <xsl:variable name="pos" select="position()"/>
                                <xsl:attribute name="{$names[$pos]}" select="tokenize(.,':')[2]"/>
                            </xsl:for-each>
                        </input>
                    </xsl:for-each-group>
                </inputGRP>
            </cms_data>
        </namespace>
    </xsl:template>

</xsl:stylesheet>

输出(使用任何格式正确/有效的 XML 输入。我使用样式表本身作为输入。)

<namespace>
   <cms_data>
      <inputGRP>
         <input type="text"
                defaultValue=""
                name="nickname_label"
                label="NickName Label"/>
         <input type="text"
                defaultValue=""
                name="nickname_error"
                label="NickName Error"/>
         <input type="text"
                defaultValue=""
                name="rowTitle_login"
                label="Row Heading Login"/>
         <input type="text"
                defaultValue=""
                name="title_label"
                label="Title Label"/>
         <input type="text"
                defaultValue=""
                name="title_error"
                label="Title Error"/>
      </inputGRP>
   </cms_data>
</namespace>

我不确定这是否比您目前所做的更易于维护。一个优点是通过使用xsl:param,您可以在运行时传入序列。这将允许您维护或生成独立于 XSLT 的名称和值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多