【问题标题】:Use/include a value from another node使用/包含来自另一个节点的值
【发布时间】:2014-11-13 12:19:31
【问题描述】:

我有一个 XML 文件,如下所示:

<area1>
    <settings>
        <setting name="to_include">value</setting>
    </settings>
</area1>
<area2>
    <settings>
        <setting name="where_to_include">?????</setting>
    </settings>
</area2>

我想将设置节点 “to_include” 的值包含为设置节点 “where_to_include” 的值。 我怎么能以纯 XML 的方式做到这一点? X包括?指针? XPath?联通?其他?

我希望我能做这样的事情:

<area2>
    <settings>
        <setting name="where_to_include">
            <xi:include href="SAMEFILE" xpointer="xpointer(/areas/area1/settings/setting[@name='debug'])">
                <xi:fallback>FALLBACK VALUE</xi:fallback>
        </setting>
    </settings>
</area2>

但是使用 XInclude 我无法在解析文档时引用文档本身。

【问题讨论】:

  • 显然,您还没有花时间熟悉这些 XML 技术。您需要什么取决于您使用的语言/环境。例如,有针对 Python(例如 lxml)、Java、PHP 的解决方案;有 XQuery 和 XSLT。在这里提问之前先看看 XSLT 教程怎么样?
  • 很遗憾,我没有时间熟悉所有的 XML 技术,但是当有新的需求出现时,我会尝试一步一步来。我已经在我的语言级别(PHP)有一个解决方案,但我不允许对其进行更改。原因是我想知道是否有一个纯 XML 解决方案而不改变外部环境。 (我还在我的问题中添加了一个 XPointer 示例)
  • 抱歉,我稍微误解了你的问题。您确定您的 PHP 解决方案支持 XPointer 和 XLink?
  • 是的,xincludes 指向同一个文件是不可能的。编写一个小型 XSLT 转换来执行此操作怎么样?
  • 我的 PHP 解决方案依赖于 libxml 并且所有 XML 功能都由它管理。所以是的,所有的解析都正确执行并且它支持 XPointer(s)(过去已经使用过)。

标签: xml xpath include xinclude xpointer


【解决方案1】:

我不太明白这个问题,但我想我知道你的意思。这可能不是你所追求的。您提到了 XPointer 和 XInclude,这对我来说似乎有点过头了。

这是一个 XSLT (1.0) 解决方案。样式表采用您在问题中提供的 XML 文件,并将 value 插入 ?????。 (顺便说一句,您的 XML 缺少一个包装器元素,因此它在技术上是错误的。但我想我理解您的意思。我会默默地添加 areas 作为文档元素,这就是后面的样式表的工作方式. 你可能需要调整它以适应你实际使用的 XML。)

这是样式表:

<?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" indent="yes"/>

  <xsl:template match="*">
    <xsl:variable name="n" select="name (.)"/>
    <xsl:element name="{$n}">
      <xsl:for-each select="@*">
        <xsl:copy-of select="."/>
      </xsl:for-each>
      <xsl:apply-templates select="node()"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="text()">
    <xsl:copy-of select="."/>
  </xsl:template>

  <xsl:template match="/">
    <xsl:element name="areas">
      <xsl:apply-templates select="areas"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="areas">
    <xsl:apply-templates select="area1"/>
    <xsl:apply-templates select="area2"/>
  </xsl:template>

  <xsl:template match="text()[parent::setting[ancestor::area2]]">
    <xsl:apply-templates select="preceding::area1/settings/setting/text()"/>
  </xsl:template>
</xsl:stylesheet>

样式表本质上只是复制它的输入 XML 文档,除了有一点:在处理 area2 下的 setting 时,它不复制文本,而是返回到 area1 节点并复制文本在其setting 下。您可以使用任何 XSLT 处理器(例如 xsltproc)确认这是否有效(听起来您可以使用一些非平凡的 XML 功能,所以这应该非常简单)。只需对value 进行一些更改,然后在更改后的 XML 文档上运行样式表。

【讨论】:

  • 请停止发布糟糕的 XSLT 答案(我所说的一切 here 都适用)。正如您在 cmets 部分中看到的那样,这个问题在聊天中进行了讨论 - 并且是关于类似于 XInclude 的方法。 OP 说他们不允许对处理 XML 文档的管道进行任何更改。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-17
  • 2018-04-11
  • 1970-01-01
  • 2014-06-26
  • 2023-03-07
  • 2015-05-24
相关资源
最近更新 更多