我查看了this POST,发现它几乎就是我需要做的。然而,考虑到这篇文章中的建议,我无法产生预期的产出。基本上,我尝试从包含以下内容的XML($ManifestFile
)文件中导入</parameter>
元素:
<?xml version="1.0" encoding="utf-8"?>
<plasterManifest
schemaVersion="1.1"
templateType="Project" xmlns="http://www.microsoft.com/schemas/PowerShell/Plaster/v1">
<metadata>
<name>PlasterTestProject</name>
<id>4c08dedb-7da7-4193-a2c0-eb665fe2b5e1</id>
<version>0.0.1</version>
<title>Testing creating custom Plaster Template for CI/CD</title>
<description>Testing out creating a module project with Plaster for complete CI/CD files.</description>
<author>Catherine Meyer</author>
<tags></tags>
</metadata>
<parameters>
<parameter name='AuthorName' type="user-fullname" prompt="Module author's name" />
<parameter name='ModuleName' type="text" prompt="Name of your module" />
<parameter name='ModuleDescription' type="text" prompt="Brief description on this module" />
<parameter name='ModuleVersion' type="text" prompt="Initial module version" default='0.0.1' />
<parameter name='GitLabUserName' type="text" prompt="Enter the GitLab Username to be used" default="${PLASTER_PARAM_FullName}"/>
<parameter name="GitLubRepo" type="text" prompt="GitiLab repo name for this module" default="${PLASTER_PARAM_ModuleName}"/>
<parameter name='ModuleFolders' type = 'multichoice' prompt='Please select folders to include' default='0,1'>
<choice label='&Public' value='Public' help='Folder containing public functions that can be used by the user.'/>
<choice label='&Private' value='Private' help='Folder containing internal functions that are not exposed to users'/>
</parameter>
</parameters>
</plasterManifest>
我尝试导入的文档($NewManifestFile
)如下所示:
<?xml version="1.0" encoding="utf-8"?>
<plasterManifest schemaVersion="1.1" templateType="Project" xmlns="http://www.microsoft.com/schemas/PowerShell/Plaster/v1">
<metadata>
<name>test3</name>
<id>8c028f40-cdc6-40dc-8442-f5256a8c0ed9</id>
<version>0.0.1</version>
<title>test3</title>
<description>SDSKL</description>
<author>NAME</author>
<tags> </tags>
</metadata>
<parameters>
</parameters>
<content>
</content>
</plasterManifest>
我编写的代码类似于:
$ManifestFile = [xml](Get-Content ".\PlasterManifest.xml")
$NewManifestFile = [xml](Get-Content $PlasterMetadata.Path)
$NewManifestFile.plasterManifest.metadata.name
$Parameters = $ManifestFile.SelectSingleNode("//plasterManifest/parameters/parameter")
$Parameters
$NewParameters = $NewManifestFile.SelectSingleNode("//plasterManifest/parameters")
# Importing the parameters and content
foreach ($parameter in $Parameters) {
$NewParamElem = $ManifestFile.ImportNode($parameter, $true)
$NewParameters.AppendChild($NewParamElem)
}
[void]$NewManifestFile.save($PlasterMetadata.Path)
现在,它不会出错,但它也完全不会导入。似乎某个元素在某个地方没有被正确分配。我尝试了这么多替代方案,这似乎是唯一接近我想要的方案。有什么建议吗?
2条答案
按热度按时间ryevplcw1#
您当前的方法存在以下几个问题:
您并没有将源文档中的元素“导入”到目标文档中,即使这是将元素插入到目标文档的DOM中的先决条件。
.SelectSingleNode()
来选择源文档节点,尽管-我想-您的意思是使用.SelectNodes()
来选择所有<parameter>
元素。.SelectSingleNode()
/.SelectNodes()
**成功查询XPath的先决条件。以下是带注解的解决方案:
可选背景信息:
.SelectSingleNode()
/.SelectNodes()
方法,因为它们接受XPath queries,所以是最灵活、最强大的方法,用于定位XML文档中感兴趣的元素(节点),但如果输入文档声明了命名空间(如您的示例中的xmlns="http://www.microsoft.com/schemas/PowerShell/Plaster/v1"
),它们确实需要**显式的命名空间处理*:parameters
),则.SelectSingleNode()
/.SelectNodes()
将简单地返回$null
,而使用名称空间限定(名称空间前缀)的元素名称(例如,plaster:parameters
)则会失败。xmlns
-您不能将其用作符号标识符(名称xmlns
是保留的),而只需“选择”一个即可。.SelectSingleNode()
/.SelectNodes()
时,您必须在查询字符串中使用此符号标识符作为元素名称前缀;例如,如果您(自己选择的)符号标识符是plaster
,并且您要在文档中的任何位置查找元素parameters
,则可以使用查询字符串'//plaster:pararameters'
Select-Xml
cmdlet作为.SelectNodes()
的高级 Package 器,它也支持XPath查询,但使命名空间管理更容易-请参阅this answer。'/root/elem'
的等价物将是$xmlDoc.root.elem
然而,这意味着您只能使用这种表示法来访问您已经知道其在层次结构中的路径的元素-不支持查询(尽管存在支持XPath的
Select-Xml
cmdlet)。plaster:parameters
元素,则必须将其引用为parameters
。此外,在反映特定文档的元素和属性名称的本机类型属性和PowerShell添加的属性之间存在名称冲突的可能性--请参阅this answer。
简而言之:XMLDOM和PowerShell对象模型之间的Map不是--也不可能是--准确和完整的。
ffdz8vbo2#
正如mklement0所指出的,您的XML文档具有名称空间,因此在使用XPath表达式选择节点时需要一个名称空间管理器。使用点访问来选择节点可以让您绕过名称空间管理,但由于点访问并不总是以预期的方式工作,我仍然建议您坚持使用
SelectNodes()
并使用适当的名称空间管理器。