xslt - 根据父亲属性修改文本子项

Posted

技术标签:

【中文标题】xslt - 根据父亲属性修改文本子项【英文标题】:xslt - modify text child based on father attribute 【发布时间】:2021-10-01 20:57:09 【问题描述】:

所以,我的问题似乎很简单,但我被困住了。我想根据 id 属性在 xml 中填充文本元素,我的 xml 是一个如下所示的 PageXML:

<?xml version="1.0" encoding="UTF-8"  standalone="yes"?>
<PcGts xmlns="http://schema.primaresearch.org/PAGE/gts/pagecontent/2019-07-15" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schema.primaresearch.org/PAGE/gts/pagecontent/2019-07-15 http://schema.primaresearch.org/PAGE/gts/pagecontent/2019-07-15/pagecontent.xsd">
  <Metadata>
    <Creator>myself</Creator>
    <Created>2021-07-03T09:37:54.369908+00:00</Created>
        <LastChange>2021-07-03T09:37:54.369944+00:00</LastChange>

  </Metadata>
  <Page imageFilename="05.tif" imageWidth="3243" imageHeight="4077">

    <TextRegion id="eSc_dummyblock_">
      <TextLine id="eSc_line_b74d9f71" >
        <Coords points="1376,108 1390,67 1492,78 1492,166 1431,149 1407,166 1390,149 1376,156"/>
        <Baseline points="1380,112 1499,112"/>
        <TextEquiv>
          <Unicode></Unicode>
        </TextEquiv>
      </TextLine>

      <TextLine id="eSc_line_5aceacfb" >
        <Coords points="2882,173 2882,142 2947,125 2947,292 2920,288 2882,309"/>
        <Baseline points="2886,176 2954,176"/>
        <TextEquiv>
          <Unicode>toto</Unicode>
        </TextEquiv>
      </TextLine>
      
      </TextRegion>
    
  </Page>
</PcGts>

我只想传递一个 xslt 模板,以便根据 TextLine id 属性为每个 Unicode 元素填充不同的值。这样的事情必须有效,但是什么也没有发生。

import lxml.etree as ET

dom = ET.parse(filename)
xslt_root = etree.XML(
'''<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes" encoding="UTF-8" omit-xml-declaration="no"/>
  <xsl:strip-space elements="*"/>

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

  <xsl:template match="@id[. = 'eSc_line_b74d9f71']/*/Unicode/text()[. = '']">something else</xsl:template>

</xsl:stylesheet>''')

transform = ET.XSLT(xslt_root)
newdom = transform(dom)

想要的输出:

<?xml version="1.0" encoding="UTF-8"?>
<TextRegion id="eSc_dummyblock_">
  <TextLine id="eSc_line_b74d9f71">
    <Coords points="1376,108 1390,67 1492,78 1492,166 1431,149 1407,166 1390,149 1376,156"/>
    <Baseline points="1380,112 1499,112"/>
    <TextEquiv>
      <Unicode>something else</Unicode>
    </TextEquiv>
  </TextLine>
  <TextLine id="eSc_line_5aceacfb">
    <Coords points="2882,173 2882,142 2947,125 2947,292 2920,288 2882,309"/>
    <Baseline points="2886,176 2954,176"/>
    <TextEquiv>
      <Unicode/>
    </TextEquiv>
  </TextLine>
</TextRegion>

感谢您的帮助

----解决方案---

正如@michael.hor257k 所建议的那样,解决方案是在 xslt 样式表中声明相同的命名空间:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:met="http://schema.primaresearch.org/PAGE/gts/pagecontent/2019-07-15"
exclude-result-prefixes="met">

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

<xsl:template match="met:TextLine[@id='eSc_line_b74d9f71']/met:TextEquiv/met:Unicode">
    <xsl:copy>something else</xsl:copy>
</xsl:template>

</xsl:stylesheet>

【问题讨论】:

请编辑您的问题并添加预期结果。还要明确“根据TextLine id属性的不同值”的意思。 【参考方案1】:

如果您想为Unicode 元素添加值,则让您的模板与Unicode 元素匹配:

XSLT 1.0

<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:strip-space elements="*"/>

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

<xsl:template match="Unicode">
    <xsl:copy>
        <xsl:if test="../../@id='eSc_line_b74d9f71'">something else</xsl:if>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

或者简单地说:

<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:strip-space elements="*"/>

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

<xsl:template match="TextLine[@id='eSc_line_b74d9f71']/TextEquiv/Unicode">
    <xsl:copy>something else</xsl:copy>
</xsl:template>

</xsl:stylesheet>

还要注意一个属性没有子属性。并且文本节点不能为空。这些都是您的模板永远不会匹配任何内容的充分理由。

【讨论】:

感谢您的回答。事实上,我认为问题与空文本有关,但即使元素 Unicode 不为空,我也确实使用建议的 xslt 模板进行了任何转换。我只是放了一个我的 xlm 的完整示例。 你可以在这里看到我的代码:xsltfiddle.liberty-development.net/93wniUp 在这里查看为什么我的代码不适用于您的实际输入以及如何解决它:***.com/a/34762628/3016153 啊,亲爱的朋友,我被这个问题困扰了好几个小时。解决方案是在我的 xslt 样式表中声明相同的命名空间。【参考方案2】:

换行怎么样

<xsl:template match="@id[. = 'eSc_line_b74d9f71']/*/Unicode/text()[. = '']">something else</xsl:template>

<xsl:template match="*[@id = 'eSc_line_b74d9f71']/TextEquiv/Unicode"><Unicode>something else</Unicode></xsl:template>

或者,更通用的版本

<xsl:template match="*[@id = 'eSc_line_b74d9f71']/TextEquiv/Unicode"><xsl:copy>something else</xsl:copy></xsl:template>

根据您的输入,这将为您提供输出

<?xml version="1.0" encoding="UTF-8"?>
<TextRegion id="eSc_dummyblock_">
  <TextLine id="eSc_line_b74d9f71">
    <Coords points="1376,108 1390,67 1492,78 1492,166 1431,149 1407,166 1390,149 1376,156"/>
    <Baseline points="1380,112 1499,112"/>
    <TextEquiv>
      <Unicode>something else</Unicode>
    </TextEquiv>
  </TextLine>
  <TextLine id="eSc_line_5aceacfb">
    <Coords points="2882,173 2882,142 2947,125 2947,292 2920,288 2882,309"/>
    <Baseline points="2886,176 2954,176"/>
    <TextEquiv>
      <Unicode/>
    </TextEquiv>
  </TextLine>
</TextRegion>

应该如愿以偿。

【讨论】:

您好,感谢您的回答。这两个选项都是合乎逻辑的,但遗憾的是它们中的任何一个都会产生所需的输出,事实上,什么都没有发生。也许是标题声明的问题?

以上是关于xslt - 根据父亲属性修改文本子项的主要内容,如果未能解决你的问题,请参考以下文章

如何合并具有“相同父亲”、相同方法和相同 id=0 的两个节点(使用 XSLT)?

xslt将具有相同属性的相邻兄弟合并为一个,同时连接它们的文本

根据以下同级词排序-XSLT

XSLT 分组/合并子项(使用密钥)

XSLT 替换属性值和文本节点中的文本

XSLT - 根据其他属性的值复制某些属性