繁体   English   中英

使用XSLT转换动态XML

[英]Transform Dynamic XML using XSLT

我是XSLT的新手,并且已经设法使用XML,在XML中每行重复节点。 我获得了一些导入的XML,每个XML记录都有不同的元素,例如:

<?xml version="1.0" encoding="utf-8"?>
<data>
    <patient>
        <link_id>123</link_id>
        <diagnoses>
            <diabetes_type2>
                <diabetes_type2_active>True</diabetes_type2_active>
                <diabetes_type2_description>diabetes mellitus</diabetes_type2_description>
                <diabetes_type2_diagnosis_date>06051999</diabetes_type2_diagnosis_date>
            </diabetes_type2>
        </diagnoses>
    </patient>
    <patient>
        <link_id>456</link_id>
        <diagnoses>
            <chd>
                <chd_active>True</chd_active>
                <chd_description>ischaemic heart disease</chd_description>
                <chd_diagnosis_date>05071997</chd_diagnosis_date>
            </chd>
            <coad>
                <coad_active>True</coad_active>
                <coad_description>chronic obstructive airways disease</coad_description>
                <coad_diagnosis_date>28011986</coad_diagnosis_date>
            </coad>
            <depression>
                <depression_active>True</depression_active>
                <depression_description>depression</depression_description>
                <depression_diagnosis_date>28011986</depression_diagnosis_date>
            </depression>
            <myocardial_infarction>
                <myocardial_infarction_active>True</myocardial_infarction_active>
                <myocardial_infarction_description>myocardial infarction</myocardial_infarction_description>
                <myocardial_infarction_diagnosis_date>05071997</myocardial_infarction_diagnosis_date>
            </myocardial_infarction>
            <osteoarthritis>
                <osteoarthritis_active>True</osteoarthritis_active>
                <osteoarthritis_description>osteoarthritis of the knee</osteoarthritis_description>
                <osteoarthritis_diagnosis_date>28011986</osteoarthritis_diagnosis_date>
            </osteoarthritis>
            <stroke>
                <stroke_active>True</stroke_active>
                <stroke_description>cerebrovascular accident</stroke_description>
                <stroke_diagnosis_date>01011996</stroke_diagnosis_date>
            </stroke>
        </diagnoses>
    </patient>
</data>

我需要导入诊断值,但我不想对可能出现的所有数百种可能值进行硬编码。 我希望有一种方法可以动态引用这些元素,而不管它们的元素名称如何。 我通常会使用这样的东西:

    <xsl:for-each select="./data/patient/diagnoses">
            <ROW MODID="" RECORDID="">
                <COL>
                    <DATA>
                        <xsl:value-of select="../../link_id"/>
                    </DATA>
                </COL>
                <COL>
                    <DATA>
                        <xsl:value-of select="./type"/>
                    </DATA>
                </COL>
                <COL>
                    <DATA>
                        <xsl:value-of select="./description"/>
                    </DATA>
                </COL>
                <COL>
                    <DATA>
                        <xsl:value-of select="./active"/>
                    </DATA>
                </COL>
                <COL>
                    <DATA>
                        <xsl:value-of select="./diagnosis_date"/>
                    </DATA>
                </COL>
            </ROW>
        </xsl:for-each>

但不确定如何针对我现在正在使用的动态元素进行修改。

您可以使用*来引用任何名称的元素,并使用name()local-name()函数动态获取元素名称,例如:

<?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="/">
      <TABLE>
        <xsl:for-each select="./data/patient/diagnoses/*">
          <xsl:variable name="diagnose" select="name()"/>
          <ROW MODID="" RECORDID="">
            <COL>
              <DATA>
                <xsl:value-of select="../../link_id"/>
              </DATA>
            </COL>
            <COL>
              <DATA>
                <xsl:value-of select="./*[name()=concat($diagnose, '_description')]"/>
              </DATA>
            </COL>
            <COL>
              <DATA>
                <xsl:value-of select="./*[name()=concat($diagnose, '_active')]"/>
              </DATA>
            </COL>
            <COL>
              <DATA>
                <xsl:value-of select="./*[name()=concat($diagnose, '_diagnosis_date')]"/>
              </DATA>
            </COL>
          </ROW>
        </xsl:for-each>
      </TABLE>
    </xsl:template>
</xsl:stylesheet>

Xsltransform.net Demo

怎么样....(这是OP接受的一种更好,更简单的解决方案!)

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

<xsl:template match="data">
  <TABLE>
    <HEADER>
      <COL><DATA>Link</DATA></COL>
      <COL><DATA>Type</DATA></COL>
      <COL><DATA>active</DATA></COL>
      <COL><DATA>description</DATA></COL>
      <COL><DATA>diagnosis_date</DATA></COL>
    </HEADER>
    <xsl:apply-templates select="patient/diagnoses/*" />
  </TABLE>
</xsl:template>

<xsl:template match="diagnoses/*">
  <ROW>
    <COL><DATA><xsl:value-of select="../../link_id" /></DATA></COL>
    <COL><DATA><xsl:value-of select="local-name()" /></DATA></COL>
    <xsl:apply-templates />    
  </ROW>
</xsl:template>

<xsl:template match="*">
  <COL><DATA><xsl:value-of select="." /></DATA></COL>
</xsl:template>  

</xsl:stylesheet>

当应用于您提供的输入文档时,此转换产生输出...

<table>
    <header>
        <col>
            <data>Link</data>
        </col>
        <col>
            <data>Type</data>
        </col>
        <col>
            <data>active</data>
        </col>
        <col>
            <data>description</data>
        </col>
        <col>
            <data>diagnosis_date</data>
        </col>
    </header>
    <row>
        <col>
            <data>123</data>
        </col>
        <col>
            <data>diabetes_type2</data>
        </col>
        <col>
            <data>True</data>
        </col>
        <col>
            <data>diabetes mellitus</data>
        </col>
        <col>
            <data>06051999</data>
        </col>
    </row>
    <row>
        <col>
            <data>456</data>
        </col>
        <col>
            <data>chd</data>
        </col>
        <col>
            <data>True</data>
        </col>
        <col>
            <data>ischaemic heart disease</data>
        </col>
        <col>
            <data>05071997</data>
        </col>
    </row>
    <row>
        <col>
            <data>456</data>
        </col>
        <col>
            <data>coad</data>
        </col>
        <col>
            <data>True</data>
        </col>
        <col>
            <data>chronic obstructive airways disease</data>
        </col>
        <col>
            <data>28011986</data>
        </col>
    </row>
    <row>
        <col>
            <data>456</data>
        </col>
        <col>
            <data>depression</data>
        </col>
        <col>
            <data>True</data>
        </col>
        <col>
            <data>depression</data>
        </col>
        <col>
            <data>28011986</data>
        </col>
    </row>
    <row>
        <col>
            <data>456</data>
        </col>
        <col>
            <data>myocardial_infarction</data>
        </col>
        <col>
            <data>True</data>
        </col>
        <col>
            <data>myocardial infarction</data>
        </col>
        <col>
            <data>05071997</data>
        </col>
    </row>
    <row>
        <col>
            <data>456</data>
        </col>
        <col>
            <data>osteoarthritis</data>
        </col>
        <col>
            <data>True</data>
        </col>
        <col>
            <data>osteoarthritis of the knee</data>
        </col>
        <col>
            <data>28011986</data>
        </col>
    </row>
    <row>
        <col>
            <data>456</data>
        </col>
        <col>
            <data>stroke</data>
        </col>
        <col>
            <data>True</data>
        </col>
        <col>
            <data>cerebrovascular accident</data>
        </col>
        <col>
            <data>01011996</data>
        </col>
    </row>
</table>

替代版本

在上文中,我假设active,description和diagnostic_date元素是固定的,并且顺序固定。 如果输入文档可以具有可变范围的属性(例如/ data / Patient / diagnoses / coad / coad_myproperty)或〜_active,〜_description,〜_diagnosis_date属性不是固定顺序的,请尝试使用此替代(更动态)的版本...

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

<xsl:variable name="fields" select="
  distinct-values(
    /data/patient/diagnoses/*/*
      [starts-with( local-name(), concat( local-name(..),'_'))]
      /substring(   local-name(), string-length( local-name(..))+2))"
  />

<xsl:template match="data">
  <TABLE>
    <HEADER>
      <COL><DATA>Link</DATA></COL>
      <COL><DATA>Type</DATA></COL>
      <COL><DATA>active</DATA></COL>
      <xsl:for-each select="$fields">
        <COL><DATA><xsl:value-of select="." /></DATA></COL>
      </xsl:for-each>
    </HEADER>
    <xsl:apply-templates select="patient/diagnoses/*" />
  </TABLE>
</xsl:template>

<xsl:template match="diagnoses/*">
  <ROW>
    <COL><DATA><xsl:value-of select="../../link_id" /></DATA></COL>
    <COL><DATA><xsl:value-of select="local-name()" /></DATA></COL>
    <xsl:variable name="this"    select="." as="element()" />
    <xsl:variable name="disease" select="local-name()" />
    <xsl:for-each select="for $f in $fields return concat($disease,'_',$f)">
      <COL><DATA>
        <xsl:value-of select="$this/*[local-name()=current()]" />
      </DATA></COL>
    </xsl:for-each>
  </ROW>
</xsl:template>

</xsl:stylesheet>

如果诊断值始终以已知顺序给出,则可以简单地执行以下操作:

<xsl:template match="/data">
    <xsl:for-each select="patient/diagnoses/*">
        <ROW MODID="" RECORDID="">
            <COL><DATA><xsl:value-of select="../../link_id"/></DATA></COL>
            <COL><DATA><xsl:value-of select="name()"/></DATA></COL>
            <xsl:for-each select="*">
                <COL><DATA><xsl:value-of select="."/></DATA></COL>
            </xsl:for-each>
        </ROW>
    </xsl:for-each>
</xsl:template>

尽管我怀疑您想将日期转换为自己的日期格式,所以也许:

<xsl:template match="/data">
    <xsl:for-each select="patient/diagnoses/*">
        <ROW MODID="" RECORDID="">
            <COL><DATA><xsl:value-of select="../../link_id"/></DATA></COL>
            <COL><DATA><xsl:value-of select="name()"/></DATA></COL>
            <COL><DATA><xsl:value-of select="*[1]"/></DATA></COL>
            <COL><DATA><xsl:value-of select="*[2]"/></DATA></COL>
            <xsl:variable name="date" select="*[3]"/>
            <COL><DATA>
                <xsl:value-of select="substring($date, 1, 2)"/>
                <xsl:text>/</xsl:text>
                <xsl:value-of select="substring($date, 3, 2)"/>
                <xsl:text>/</xsl:text>
                <xsl:value-of select="substring($date, 5, 4)"/>
            </DATA></COL>
        </ROW>
    </xsl:for-each>
</xsl:template>

假设您要d/m/y

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM