【问题标题】:How is XML inheritance typically handled in XSLT?XSLT 中通常如何处理 XML 继承?
【发布时间】:2011-07-07 13:36:06
【问题描述】:

我有一个 XML 文件,它在许多地方使用 base 属性来继承多个文档中的数据类型。我想要的是使用 XSLT 处理文档,就好像它正在处理继承了所有内容的文档一样。尽管我对 XSLT 的了解非常少,但我还没有看到明显的方法来做到这一点。

当我说继承时,我指的是允许数据类型从另一个数据类型继承的 XML 基本属性。例如;

<parameter name="DeviceLog" access="readOnly">
    <description>Vendor-specific log(s).</description>
</parameter>
<parameter base="DeviceLog" access="readOnly" activeNotify="canDeny">
</parameter>

这里的描述标签应该被第二个参数继承。因此,当我的 XSLT 脚本处理第二个参数时,它会将其读取为

<parameter name="DeviceLog" access="readOnly" activeNotify="canDeny">
    <description>Vendor-specific log(s).</description>
</parameter>

也许这不能做?

编辑: 我所说的继承不是标准的。它只是由生成我正在处理的 XML 文件的人创建的东西。我必须编写自己的解决方案来合并所有“继承”的元素和属性。

【问题讨论】:

  • “XML 继承”没有一个广为人知的概念。你这是什么意思?您的问题高度缺乏诸如源 XML 文档、转换的所需输出以及转换的所有所需属性/规则/要求的解释等必要组成部分。请编辑问题并提供这些。
  • @Dimitre 自从我更新了我的问题以来,您的评论得到了很多赞成票,所以我一定遗漏了一些东西。我不明白还需要什么来回答这个问题。也许你能帮帮我?
  • 您没有提到是否存在属性继承。此外,如果基础和派生都具有相同名称的元素/属性,会发生什么情况?另外,“多个文档”是什么意思?请给出一个完整的例子来回答所有这些问题。
  • 另外,更正提供的 XML -- 这不是一个格式良好的 XML 文档,甚至不是一个格式良好的 XML 片段。

标签: xml xslt


【解决方案1】:

XSLT 将 XML 文档作为输入树,然后生成输出。当输出也是 XML 时,它有效地将输入树转换为输出树。这意味着您在阅读时没有空间更改输入树。据我所知,您也不能真正将部分结果作为模板的输入传递。所以我的建议是连续执行两个 XSLT 转换。一个用于将输入转换为所需的虚拟中间结果,另一个用于执行这种格式所需的实际处理,其中继承的结构被折叠成扁平结构。

第一步的 XSLT 可能会以此为基础:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="node()|@*">
        <xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>
    </xsl:template>
    <xsl:template match="//*[@base]">
        <xsl:variable name="base" select="@base"/>
        <xsl:copy><xsl:copy-of select="./node() | ./@*[local-name() != 'base'] | //*[@name=$base]/@*"></xsl:copy-of><xsl:copy-of select="//*[@name=$base]/node()"/></xsl:copy>
    </xsl:template>
</xsl:stylesheet>

这将改变以下...

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <test name="one" hello="kitty">
        <one hello="world">test</one>
        <two/>
    </test>
    <bogus att="none">
        <test/>
    </bogus>
    <test base="one" run="true" hello="kitty">
        <three/>
    </test>
</root>

...进入这个:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <test name="one" hello="kitty">
        <one hello="world">test</one>
        <two/>
    </test>
    <bogus att="none">
        <test/>
    </bogus>
    <test name="one" run="true" hello="kitty">
        <three/>
        <one hello="world">test</one>
        <two/>
    </test>
</root>

有一些边缘情况需要解决。如果具有name 属性的元素和具有base 属性的元素都具有相同名称的属性,则处理器将检测到这一点并只保留一个。 hello="kitty" 就是这种情况。但如果这些属性有不同的值,结果就很难预测。您可能还希望抑制初始的name 轴承元素。为此,只需添加一个模板,该模板不会为具有 name 属性的元素输出任何内容。

此转换后,您可以应用第二个。我假设您的“继承”嵌套只有一个深度,每个基础只出现一个名称。如果这不是真的,那么这个策略可能不起作用。细节交给你处理。

【讨论】:

  • PS:我喜欢你的头像,toc777 :D
  • 谢谢。我想我可能不得不做这样的事情。我真的很惊讶我找不到为我做这件事的工具。这似乎是人们需要经常做的事情。
  • 嗯,您在 XML 中的层次结构概念是由您的格式发明的。它并不真正适合任何 XML 规范,因此没有任何特定的支持也就不足为奇了。 XML Schema 具有继承的复杂类型的概念,因此可感知模式的 XSLT 处理器可能能够对其进行处理。除此之外,我会说将文档解组为编程模型(如 JAXB)并在其中进行处理。
  • 但不是 XML 规范中的基本属性吗?无论如何,我有 XML 文件的架构,因此架构感知 XSLT 处理器可能会工作。我去看看。
  • 我仍然不明白为什么不存在执行此操作的工具,但在网上搜索数小时后我找不到任何工具。我必须按照你的建议去做。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-30
  • 2017-06-12
  • 2011-04-23
  • 2011-06-10
  • 2011-02-18
  • 2012-04-12
相关资源
最近更新 更多