我正在使用Powershell和System.Xml.XmlTextWriter类构建XML文档。 我需要在此文档中插入一个xml节点。此XML节点必须来自Web服务调用。
我已经能够使用正确的XML
$kalSes = Invoke-RestMethod -uri $TokenUri -Method Post -Body $kstring | Select-Xml -XPath "/"
我现在需要将此XML插入到我正在构建的文档中
XMLTextWriter $XW
$XW.WriteStartElement("CustomData")
$XW.WriteNode($kalSes,'false')
$XW.WriteEndElement()
此操作失败并显示错误
找不到“WriteNode”的重载和参数count:“2”。
正如MSDN上的文档所述,WriteNode()
方法需要一个XmlReader对象。我尝试使用$kalSes
XML创建XML阅读器对象,然后将其提供给WriteNode()方法..但是没有快乐。
New-Object System.Xml.XmlTextReader($kalSes)
New-Object:找不到构造函数。找不到合适的类型构造函数 System.Xml.XmlTextReader。
我尝试将$kalSes
写入文件,然后使用XML阅读器再次阅读它。将此提供给WriteNode
会产生错误
Invoke-RestMethod:进程无法访问文件'PATH \ xml.txt' 因为它正被另一个进程使用。
我认为写入方法在读取方法尝试读取文件的同时锁定文件。即使我能让这个apprach工作,我相信它会在数百个输入值上非常缓慢
最后
我尝试使用WriteElementString(name,value)
方法,但这会转义xml标记
我很感激你带来的集体智慧的任何指导!
安格斯
由Jim Moyle要求 Powershell脚本
Add-Type -AssemblyName System.Web
Add-Type -AssemblyName System.Xml
# Setup some static variables
$csvpath = "{PATH}\KaltSource.csv"
$xmlpath = "{PATH}\KaltSource.xml"
# Setup Kaltura session Token retrieval
$TokenUri = "http://webkaltura.aftrs.edu.au/api_v3/index.php?service=session&action=start"
$kstring = "secret={SECRET}&type=2&partnerId={PI}"
#Setup Kaltura metadata retrieval
$metadataURI = "http://webkaltura.aftrs.edu.au/api_v3/index.php?service=metadata_metadata&action=list"
# This is a kaltura Session string this will have to be generated before the script is run and pased here
$kalSes = Invoke-RestMethod -uri $TokenUri -Method Post -Body $kstring | Select-Xml -XPath "/xml/result"
Write-Host ($kalSes)
#setup xml document writer
$XW = New-Object System.Xml.XmlTextWriter($xmlpath,$Null)
$XW.Formatting = "Indented"
$XW.Indentation = "4"
#XML Declaration
$XW.WriteStartDocument()
$XW.WriteStartElement("mrss")
$XW.WriteAttributeString("xmlns:xsd","http://www.w3.org/2001/XMLSchema")
$XW.WriteAttributeString("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance")
$XW.WriteAttributeString("xsi:noNamespaceSchemaLocation","ingestion.xsd")
$XW.WriteStartElement("channel")
#Begin writing each item within loop
Import-CSV $csvpath | ForEach-Object {
# get the custom data from kaltura
# Custom data is XML embedded in a XML response object. The embedded XML has been http encoded. We have to extract the desired information
# from the XML resonse object then http decode to get proper XML to insert into our document
$kstring = "ks="+$kalSes+"&filter%3AobjectIdEqual="+$_.Entity+"&filter%3AobjectType=KalturaMetadataFilter"
$metaD = Invoke-RestMethod -uri $metadataURI -Method Post -Body $kstring | Select-Xml -XPath "/xml/result/objects/item/xml"
$metaDstr = [System.Web.HttpUtility]::HtmlDecode($metaD)
#create a xml reader
# Try to insert the XML data into an XML reader object to pass to the
# XmlTextWriter WriteNode method
#$XR = New-Object System.Xml.XmlTextReader($metaDstr)
# Set the ftp path
$ftppath = "ftp://{PRIVATE DATA}" + $_.Path
$XW.WriteStartElement("item")
$XW.WriteElementString("action","add")
$XW.WriteElementString("type","1")
$XW.WriteElementString("name",$_.name)
$XW.WriteElementString("description",$_.description)
# Handle media tags
$XW.WriteStartElement("tags")
$XW.WriteElementString("tag",$_.tags)
$XW.WriteEndElement() #close tags
# Handle the Categories
$XW.WriteStartElement("categories")
$XW.WriteElementString("category",$_.categories)
$XW.WriteEndElement() #close categories
$XW.WriteStartElement("media")
$XW.WriteElementString("mediaType",$_.media_type)
$XW.WriteEndElement() #close media
$XW.WriteStartElement("contentAssets")
$XW.WriteStartElement("content")
$XW.WriteStartElement("urlContentResource")
$XW.WriteAttributeString("url",$ftppath)
$XW.WriteEndElement() #close content
$XW.WriteEndElement() #close contentAssets
$XW.WriteStartElement("customDataItems")
$XW.WriteStartElement("customData")
$XW.WriteAttributeString("metadataProfile","{PRIVATE DATA}")
$XW.WriteNode($metaDstr,'false')
$XW.WriteEndElement() # Close customData
$XW.WriteEndElement() # Close customDataItemclear
$XW.WriteEndElement() #close item
}
$XW.WriteEndElement() #close channel
$XW.WriteEndElement() #close mrss
$XW.WriteEndDocument()
$XW.Flush()
$XW.Close()
来源CSV
name,description,tags,categories,media_type,file,Path,Entity
Top Girls,Directed by XX,student films,Student Films,1,0_intymm19.mp4,/Media/4/269/0_gqv6w2zc_0_xxv8em29_2.mp4,0_03yxzyuy
从WS调用返回的XML
<?xml version="1.0" encoding="utf-8"?>
<xml>
<result>
<objectType>KalturaMetadataListResponse</objectType>
<objects>
<item>
<objectType>KalturaMetadata</objectType>
<id>159</id>
<partnerId>106</partnerId>
<metadataProfileId>1</metadataProfileId>
<metadataProfileVersion>17</metadataProfileVersion>
<metadataObjectType>1</metadataObjectType>
<objectId>0_9jf3ii26</objectId>
<version>7</version>
<createdAt>1382305441</createdAt>
<updatedAt>1421895691</updatedAt>
<status>1</status>
<xml><metadata>
<LOGLINE>An emotional roller-coaster that explores the inner workings of an anxious mind.</LOGLINE>
<YearVideoMade>2011</YearVideoMade>
<LevelOfStudy>Graduate Diploma</LevelOfStudy>
<SYNOPSIS>A handcuffed prisoner shuffles in to a dimly lit police interrogation room. He tries to talk his way out of a grim situation - bargaining, pleading until, finally becoming apoplectic, he tears his clothes off and collapses naked to the floor. Lying there, he accepts his situation... then heaves himself up and steps back outside towards his fate.</SYNOPSIS>
<Director>Lisa Hoppe</Director>
<DirectorID>19577</DirectorID>
<Writer>Lisa Hoppe</Writer>
<WriterID>19577</WriterID>
<Producer>Anna Slowiak</Producer>
<ProducerID>19084</ProducerID>
<Cinematographer>Emma Paine</Cinematographer>
<CinematographerID>18089</CinematographerID>
<Editor>Andrew Simmons</Editor>
<EditorID>19074</EditorID>
<LocationSound>Martin Cox</LocationSound>
<LocationSoundID>16638</LocationSoundID>
<PostSound>Andrew Simmons</PostSound>
<PostSoundID>19074</PostSoundID>
<Composer>Jenna Cave</Composer>
<ComposerID>19399</ComposerID>
<AreaOfSpecialisation>Directing</AreaOfSpecialisation>
<AFTRSSTUDENTKEYCREATIVECREW>Lisa Hoppe: director</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Lisa Hoppe/Bobbie Waterman: writer</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Anna Slowiak: producer</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Emma Plaine: cinematographer</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Andrew Simmons: editor</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Vicki Nhieu: production designer</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Martin Cox: location sound</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Andrew Simmons: post sound</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Jenna Cave: composer</AFTRSSTUDENTKEYCREATIVECREW>
</metadata></xml>
</item>
</objects>
<totalCount>1107</totalCount>
</result>
<executionTime>0.28421306610107</executionTime>
</xml>
感兴趣的解码数据
<metadata>
<LOGLINE>An emotional roller-coaster that explores the inner workings of an anxious mind.</LOGLINE>
<YearVideoMade>2011</YearVideoMade>
<LevelOfStudy>Graduate Diploma</LevelOfStudy>
<SYNOPSIS>A handcuffed prisoner shuffles in to a dimly lit police interrogation room. He tries to talk his way out of a grim situation - bargaining, pleading until, finally becoming apoplectic, he tears his clothes off and collapses naked to the floor. Lying there, he accepts his situation... then heaves himself up and steps back outside towards his fate.</SYNOPSIS>
<Director>Lisa Hoppe</Director>
<DirectorID>19577</DirectorID>
<Writer>Lisa Hoppe</Writer>
<WriterID>19577</WriterID>
<Producer>Anna Slowiak</Producer>
<ProducerID>19084</ProducerID>
<Cinematographer>Emma Paine</Cinematographer>
<CinematographerID>18089</CinematographerID>
<Editor>Andrew Simmons</Editor>
<EditorID>19074</EditorID>
<LocationSound>Martin Cox</LocationSound>
<LocationSoundID>16638</LocationSoundID>
<PostSound>Andrew Simmons</PostSound>
<PostSoundID>19074</PostSoundID>
<Composer>Jenna Cave</Composer>
<ComposerID>19399</ComposerID>
<AreaOfSpecialisation>Directing</AreaOfSpecialisation>
<AFTRSSTUDENTKEYCREATIVECREW>Lisa Hoppe: director</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Lisa Hoppe/Bobbie Waterman: writer</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Anna Slowiak: producer</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Emma Plaine: cinematographer</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Andrew Simmons: editor</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Vicki Nhieu: production designer</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Martin Cox: location sound</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Andrew Simmons: post sound</AFTRSSTUDENTKEYCREATIVECREW>
<AFTRSSTUDENTKEYCREATIVECREW>Jenna Cave: composer</AFTRSSTUDENTKEYCREATIVECREW>
</metadata>
答案 0 :(得分:0)
因此,如果我使用将xml流式传输到文件的方法,那么我无法使其工作,因此我将其更改为在变量中操作xml。然后你可以拿出最终结果并随心所欲地做它。
希望代码中的注释足以帮助您理解我的方法,如果不发表评论,我会尝试解释。
另一种方法是创建一个自定义PoSH对象,正常操作并使用export-clixml将其写入磁盘。
可能有比这更好,更优雅的解决方案,但是我使用这个问题作为一种方式让我离开了解更多关于xml操作的知识。所以这是第一遍我们应该说....
cls
Add-Type -AssemblyName System.Xml
#csv details
$csvpath = "\\path\KaltSource.csv"
#create root of xml file as a here string
$baseString =
@"
<?xml version="1.0"?>
<mrss xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ingestion.xsd">
<channel>
</channel>
</mrss>
"@
#Convert string to xml
$baseXml = [xml]$baseString
#pass csv details to foreach
Import-CSV $csvpath | ForEach-Object {
$ftpPath = "ftp://yourdomain.com" + $_.Path
#create here string xml from csv input
$csvString =
@"
<?xml version="1.0" encoding="UTF-8"?>
<item>
<action>add</action>
<type>1</type>
<name>$($_.name)</name>
<description>$($_.description)</description>
<tags>
<tag>$($_.tags)</tag>
</tags>
<categories>
<category>$($_.categories)</category>
</categories>
<media>
<mediaType>$($_.media_type)</mediaType>
</media>
<contentAssets>
<content>
<urlContentResource url="$ftppath"/>
</content>
<customDataItems>
<customData metadataProfile="private data"/>
</customDataItems>
</contentAssets>
</item>
"@
#convert string to xml
$csvXml = [xml]$csvString
#get metadata from REST in your case, in my testing I got from a local file
$metaDstr = Get-Content "\\path\film.xml"
[xml]$metaDstr = $metaDstr
#add metadata node into the node we created from the csv input
$csvXml.item.AppendChild($csvXml.ImportNode($metaDstr.metadata, $true))
#As channel is an empty node we need to select it before adding anything into it
$node = $baseXml.mrss.SelectSingleNode("channel")
#Add all the information we've gathered into the base xml we set up at the top
$node.AppendChild($baseXml.ImportNode($csvXml.item, $true))
}
答案 1 :(得分:0)
为了以后可能会发现这篇文章的其他人的利益,我提供了一个我发现上述问题的解决方案。 @JimMoyle提供了一个非常可行的解决方案,但我想发布一个替代方案。
根据上面的信息,我感兴趣的数据有效负载是在XML信封中进行html编码
$payload = Invoke-RestMethod -uri $metadataURI -Method Post -Body $kstring | Select-Xml -XPath "/xml/result/objects/item/xml"
这是作为字符串对象返回的,该对象经过html解码并转换为XML文档。
[xml] $metaD = [System.Web.HttpUtility]::HtmlDecode($payload)
然后将此XML文档转换为XML节点
$nodeReader = New-Object System.Xml.XmlNodeReader($metaDstr)
将XML节点制作成XPathDocument
$XPD = New-Object System.Xml.XPath.XPathDocument($nodeReader)
构造成XPathnavigator
$XPreader = $XPD.CreateNavigator()
XPathenavigator是XmlTextWriter.WriteNode()
方法
$XW.WriteNode($XPreader,'false')