XSLT:将XMS复制到XML并更新文件结构

时间:2013-03-17 17:52:12

标签: xslt xml-parsing

我有一个XML文件,其元素<Database>有两个子元素<Patients> and <Hospitals>。每个<Patients>都有一个子元素<Patient>,其名称指定为属性。每家医院都有一个属性名称,例如:<Hospital name="JR"和子元素<Patients>,其中包含子元素<Patient name="XY">

我想通过复制患者的结构来更新文件,但是要添加医院信息。作为患者姓名的附加属性,或作为子元素。有什么想法吗?

编辑:谢谢Tim,这是样本。

<Database>
<Patients>
    <Patient name="Salvatore"/>
    <Patient name="Luca"/>
</Patients>
<Hospitals>
    <Hospital name="JR">
        <Patients>
            <Patient name="Salvatore"/>
        </Patients>
    </Hospital>
    <Hospital name="LondonGeneral">
        <Patients>
            <Patient name="Luca"/>
        </Patients>
    </Hospital>
</Hospitals>
</Database>

输出应如下所示:

    <?xml version="1.0" encoding="UTF-8"?>
<Database>
    <Patients>
        <Patient name="Salvatore" hospital="JR"/>
        <Patient name="Luca" hospital="LondonGeneral"/>
    </Patients>
    <Hospitals>
        <Hospital name="JR">
            <Patients>
                <Patient name="Salvatore"/>
            </Patients>
        </Hospital>
        <Hospital name="LondonGeneral">
            <Patients>
                <Patient name="Luca"/>
            </Patients>
        </Hospital>
    </Hospitals>
</Database>

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

假设每个患者姓名仅包含在一个Hospital元素中,则以下内容应该起作用

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:key name="hospitalPatientByName"
           match="Hospital/Patients/Patient"
           use="@name" />

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

  <xsl:template match="Patient[not(ancestor::Hospital)]">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:attribute name="hospital">
        <xsl:value-of select="key('hospitalPatientByName', @name)/ancestor::Hospital/@name" />
      </xsl:attribute>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

我们通过患者姓名在Patient元素下查找相应的Patient来处理每个顶级Hospital元素,然后提取包含医院的名称。

如果相同名称的Patient可能不止一个Hospital,那么我会使用子元素而不是属性

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:key name="hospitalPatientByName"
           match="Hospital/Patients/Patient"
           use="@name" />

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

  <xsl:template match="Patient[not(ancestor::Hospital)]">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:apply-templates select="key('hospitalPatientByName', @name)/ancestor::Hospital" mode="in-patient" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Hospital" mode="in-patient">
    <xsl:copy><xsl:apply-templates select="@*" /></xsl:copy>
  </xsl:template>

</xsl:stylesheet>

鉴于您的样本输入,这将产生

<Database>
<Patients>
    <Patient name="Salvatore"><Hospital name="JR"/></Patient>
    <Patient name="Luca"><Hospital name="LondonGeneral"/></Patient>
</Patients>
<Hospitals>
    <Hospital name="JR">
        <Patients>
            <Patient name="Salvatore"/>
        </Patients>
    </Hospital>
    <Hospital name="LondonGeneral">
        <Patients>
            <Patient name="Luca"/>
        </Patients>
    </Hospital>
</Hospitals>
</Database>

如果(比如)Luca也在JR患者名单中,那么你就会列出两家医院,即

<Patient name="Luca">
  <Hospital name="JR"/>
  <Hospital name="LondonGeneral"/>
</Patient>