【问题标题】:XSL to transform XML filtering out only element and attribute values?XSL 转换 XML 只过滤出元素和属性值?
【发布时间】:2012-09-07 21:58:17
【问题描述】:

我需要将以下 XML 转换为具有相同元素和属性的 XML,但可以本地化的值除外 - 基本上是英文短语。

某些元素 (<footnote>) 和属性是可选的 (<display_data_type>),我希望能够通用地执行此操作 - 无需为每个元素设置模板。这可能吗?

最终目标是能够将 XML 的默认版本与本地化版本进行比较,忽略本地化字符串。

例如:

<data_schema>
    <field symbol="ACCOUNT" type="string" name="Account Number">
        <validators>
            <maxlength>6</maxlength>
        </validators>
        <description>The account number</description>
        <example>123456</example>
        <default_value></default_value>
    </field>
    <field symbol="POSTAL_CODE" type="string" name="Postal Code">
        <description>Postal Code for account</description>
        <example>22022</example>
        <footnote>Does not apply to certain accounts</footnote>
        <default_value></default_value>
    </field>
    <field symbol="DISCOUNT" type="string" name="Discount Percentage" display_data_type="percentage">
        <description>Descount determined by account</description>
        <example>1.5%</example>
        <default_value></default_value>
    </field>
</data_schema>

将转换为:

<data_schema>
    <field symbol="ACCOUNT" type="string" name="">
        <validators>
            <maxlength>6</maxlength>
        </validators>
        <description/>
        <example/>
        <default_value/>
    </field>
    <field symbol="POSTAL_CODE" type="string" name="">
        <description/>
        <example/>
        <footnote/>
        <default_value/>
    </field>
    <field symbol="DISCOUNT" type="string" name="" display_data_type="percentage">
        <description/>
        <example/>
        <default_value/>
    </field>
</data_schema>

【问题讨论】:

  • 就可本地化的问题而言,这并不重要。任何排除任何元素或属性的示例都是可以接受的。如果它确实重要,示例输入和输出指示哪些特定元素是可本地化的。

标签: xml xslt localization xmldiff


【解决方案1】:

这是另一种方法。这个基于“身份转换”的 XSLT 设计模式,它基本上只是按原样复制所有节点。

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

您可以扩展它以添加其他模板匹配项以匹配您要对其执行特定操作的节点,在您的情况下是删除文本。所需的模板将取决于转换的确切规则。

如果您希望从特定元素和属性中删除文本,您可以添加以下两个模板,以复制节点但不包含文本:

<xsl:template match="description|example|footnote|default_value">
   <xsl:copy/>
</xsl:template>

<xsl:template match="@name">
   <xsl:attribute name="{name()}"/>
</xsl:template>

因此,在这种情况下,元素 descriptionexamplefootnotedefault_value 的文本已被删除,以及 @name 属性。所有其他节点都将按原样复制其文本。

另一方面,如果您有一个特定的元素和属性列表想要保持不变,您可以像这样添加模板

<xsl:template match="field/*[not(self::validators)]">
   <xsl:copy/>
</xsl:template>

<xsl:template match="@symbol|@type|@display_data_type">
   <xsl:copy/>
</xsl:template>

<xsl:template match="@*">
   <xsl:attribute name="{name()}"/>
</xsl:template>

因此,对于 validators 元素,您实际上是在说,删除所有不是 validators 元素的内容。 validators 元素将被身份转换模板复制。对于属性,我展示了一种稍微不同的方法,其中明确列出了要保留的属性,并且您有第二个模板可以从所有其他属性中删除文本。

这是本例中的两个完整 XSLT。

第一个用于从特定节点中删除文本

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="description|example|footnote|default_value">
      <xsl:copy/>
   </xsl:template>

   <xsl:template match="@name">
      <xsl:attribute name="{name()}"/>
   </xsl:template>

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

第二个用于将文本保存在特定节点中

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="field/*[not(self::validators)]">
      <xsl:copy/>
   </xsl:template>

   <xsl:template match="@symbol|@type|@display_data_type">
      <xsl:copy/>
   </xsl:template>

   <xsl:template match="@*">
      <xsl:attribute name="{name()}"/>
   </xsl:template>

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

对于您的示例文档,两者都应该产生相同的输出:

<data_schema>
   <field symbol="ACCOUNT" type="string" name="">
      <validators>
         <maxlength>6</maxlength>
      </validators>
      <description/>
      <example/>
      <default_value/>
   </field>
   <field symbol="POSTAL_CODE" type="string" name="">
      <description/>
      <example/>
      <footnote/>
      <default_value/>
   </field>
   <field symbol="DISCOUNT" type="string" name="" display_data_type="percentage">
      <description/>
      <example/>
      <default_value/>
   </field>
</data_schema>

【讨论】:

  • 谢谢蒂姆。很有帮助的解释。我的主要目标只是提供最简洁易懂的 xslt,而不必为每个可本地化的属性/元素提供单独的模板。
【解决方案2】:

这是一个例子。应用这样的模板时,应创建树的副本,减去非符号或类型属性的文本区域和属性文本。

<xsl:template match="*">
  <xsl:element name="{name()}">
    <xsl:for-each select="@*">
      <xsl:choose>
        <xsl:when test="name() = 'symbol' or name() = 'type'">
          <xsl:copy-of select="."/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:attribute name="{name()}"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>  

    <xsl:apply-templates select="*"/>
  </xsl:element>
</xsl:template>

【讨论】:

  • 正是我需要的。谢谢!
  • 错了。显然,答案海报和 OP 都没有测试过这个解决方案。
  • 肖恩,你错了 - 这行得通,足以满足我的目的。再试一次。
  • 输出与您列出的预期输出不匹配。在 SO 中,当您提出问题并列出一些预期输出时,人们认为这意味着这是对任何建议答案的测试。如果建议的答案与列出的预期输出不匹配,则它是错误的。如果 OP 然后说它没有错,那么根据定义,这个问题是模棱两可的。关于 SO 的问题需要符合常见问题解答中指定的格式。问题需要具体、狭窄和不含糊。更多...
  • 虽然在常见问题解答中没有指定,但关于 XSLT,顶级 XSLT 回答者总是需要另外一个用例(示例输入加上预期输出),XSLT 版本(1.0、2.0 或 3.0) , 如果是 1.0 那么是服务器端还是客户端。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-17
相关资源
最近更新 更多